Akhilesh Verma
Akhilesh Verma

Reputation: 35

Spring-Retry: Create custom annotation similar to @Retryable

I have a number of microservices which needs a retry mechanism if connection with database fails. This retry mechanism has to be triggered when SQLException and HibernateException occurs. Passing a proper interceptor in @Retryable will work but this has to be incorporated in all the microservices. Can we make a custom annotation similar to @Retryable like @DatabaseRetryable which will trigger retry on SQLException and HibernateException.

Usage of this annotation would be roughly as following

@DatabaseRetryable
void executeQuery()
{
    //some code
}

Upvotes: 0

Views: 2406

Answers (2)

geld0r
geld0r

Reputation: 850

You can solve this by creating a meta-annotation with your desired name:

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Retryable(
    value = { SQLException.class, HibernateException.class }
)
public @interface DatabaseRetryable {
}

You can use this meta-annotation as drop-in replacement for @Retryable. The same constraints apply - it just allows to configure some common behavior in a single place. You might also use this to use the same backOff for all related services.

Upvotes: 1

Konstantin
Konstantin

Reputation: 453

There are several approaches for this:

  1. Use the spring-retry project and integrate that into your application. But as you stated this is not what you want. This framework provides more than just simple retries on exceptions and is much more extensive than it seems at first glance.
  2. Use an AOP (Aspect Oriented Programming) model and libraries like AspectJ
  3. Create a custom annotation, introspect your classes before you run the methods and see if it annotated with the @CustomRetryable and then run the retry method or not. This however is not very simple and needs to be properly integrated with your classes. Which in term depends on how your application is designed etc.
  4. If you want to keep it as simple as possible: create a helper class to perform retries for you.

My suggestion is look at your problem, is you desired solution needed for more than just these retries? Then go with a library. Is it simple one/two use case scenarios then go with a utility class/method approach.

A very crude example of this could be a util class:

import java.util.logging.Level;
import java.util.logging.Logger;

public class RetryOperation {
    public static void main(String args[]) {
        retryOnException(() -> {throw new Exception();} , Exception.class, 4);
    }

    interface CustomSupplier<T> {
        T get() throws Exception;
    }
    static <E extends Exception, T> T retryOnException(CustomSupplier<T> method, Class<E> exceptionClass, int retries) {
        if (method == null) {
            throw new IllegalArgumentException("Method may not be null");
        }
        if (exceptionClass == null) {
            throw new IllegalArgumentException("Exception type needs to be provided");
        }
        int retryCount = 0;
        T result = null;

        while (retryCount < retries) {
            try {
                result = method.get();
            } catch (Exception exception) {
                if (exceptionClass.isAssignableFrom(exception.getClass()) && retryCount < retries) {
                    // log the exception here
                    retryCount++;
                    Logger.getLogger(RetryOperation.class.getName()).log(Level.INFO, String.format("Failed %d time to execute method retrying", retryCount));
                } else {
                    throw exception;
                }
            }
        }

        return result;
    }
}

Note that this is a crude example and should only function to explain my thinking behind it. Look at what you exactly need and design from there.

Upvotes: 1

Related Questions