Skip to content
This repository has been archived by the owner on Mar 30, 2019. It is now read-only.

Feature request: Callbacks onAbort, onRetry #2

Open
dennisfischer opened this issue Aug 28, 2013 · 7 comments
Open

Feature request: Callbacks onAbort, onRetry #2

dennisfischer opened this issue Aug 28, 2013 · 7 comments

Comments

@dennisfischer
Copy link

I've looked into this API and saw that some callbacks (onAbort, onRetry) would be awesome. These should be defineable in each "RetryCallable" and provide some nice option to react on these events.

Speaking of this - the Java 7 way is easy, just extend the interface by 2 methods and add an abstract class.
Shouldn't there be a simpler solution, that I'm just not aware of?

The problem is Java 8 - lambdas. I'm not used to them so I can't provide any solution on this. What's up with you guys out there? Any idea how to do this without breaking "ctx -> method()"

@nurkiewicz
Copy link
Owner

It's actually even simpler with Java 8 (which is the primary target for this library) - simply adding default methods:

@FunctionalInterface
public interface RetryCallable<V> {

    V call(RetryContext context) throws Exception;

    default void onRetry(Throwable t) {}

    default void onAbort(Throwable t) {}

}

When onRetry()/onAbort() is not used, simplified ctx -> method() lambda syntax can be used. If callbacks are desired, more complex syntax must be used even in Java 8:

executor.getWithRetry(new RetryCallable<Integer>() {

    @Override
    public Integer call(RetryContext context) throws Exception {
        return method();
    }

    @Override
    public void onRetry(Throwable t) {
        //...
    }

    @Override
    public void onAbort(Throwable t) {
        //...
    }
})

Remember that RetryRunnable has to be enhanced this way as well.


Another solution I can think of is adding AsyncRetryExecutor-wide callbacks configuration:

executor.
        onRetry(throwable -> /* ... */).
        onAbort(throwable -> /* ... */).
        doWithRetry(ctx -> method());

AsyncRetryExecutor is immutable so onRetry()/onAbort() do not affect existing executor but create new, enhanced one. What do you think?


Last but not least, what are the intended use cases for these callbacks, except e.g. logging (built-in)? Remember that RetryPolicy is already called after each exception so you can get similar functionality by wrapping RetryPolicy.

@felipesere
Copy link

In my case I'd like to start a different action in case the operation did not succeed within the number of retries.

@nurkiewicz
Copy link
Owner

@felipesere Instead of using "failure callback" you can just register callback on returned CompletableFuture:

executor.
    getWithRetry(() -> new Socket("localhost", 8080)).
    whenComplete((socket, error) -> {
        if (socket != null) {
            //connected OK, proceed
        } else {
            log.error("Can't connect, last error:", error);
        }
    });

or more succinctly:

executor.
        getWithRetry(() -> new Socket("localhost", 8080)).
        exceptionally(throwable -> {
            //no more retries, failure callback here
        });

Does this somewhat address your issues?

@felipesere
Copy link

I'm stuck on Java 7. Does that work there too?

@nurkiewicz
Copy link
Owner

@felipesere It's possible, but much more verbose with ListenableFuture API from Guava:

final ListenableFuture<Socket> future = executor.getWithRetry(new RetryCallable<Socket>() {
    @Override
    public Socket call(RetryContext context) throws Exception {
        return new Socket("localhost", 8080);
    }
});
Futures.withFallback(future, new FutureFallback<Socket>() {
    @Override
    public ListenableFuture<Socket> create(Throwable t) throws Exception {
        //no more retries, failure callback here
        return Futures.immediateFailedFuture(t);
    }
});

@derylspielman
Copy link

I would love this feature as well. My use case is I am sending e-mails using Spring and when a MailSendException occurs the exception contains the failed messages. I'd like to retry only those messages found within the exception.

@pisarek
Copy link

pisarek commented Jan 22, 2016

Last but not least, what are the intended use cases for these callbacks, except e.g. logging (built-in)? Remember that RetryPolicy is already called after each exception so you can get similar functionality by wrapping RetryPolicy.

What do you mean by "wrapping RetryPolicy"? Could you give an example?
I too would be insterested in this addded functionality.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants