I am using the FailSafe library to handle failures and retries.
The current implementation creates the generic FailsafeExecutor
on each run -
var result = Failsafe.with(Collections.singletonList(retryPolicy))
.with(scheduler)
.<R>getAsyncExecution(execution ->
doSomething(x, y));
FaileSafe.with
definition -
public static <R, P extends Policy<R>> FailsafeExecutor<R> with(P outerPolicy, P... policies)
Since this is called on a critical path, I would really like to avoid this (the recreation of the object).
I tried initiating the FailsafeExecutor
on the class level (the class is not generic) with a <?>
-
private final FailsafeExecutor<?> executor;
but then when calling the executor I receive -
Type parameter 'R' is not within its bound; should extend 'capture<?>'
Is there any way to get over this? Some kind of way I could make this object reusable? (same with the RetryPolicy, but I guess if there is a solution for the first it would apply for the policy as well)
Thanks.
CodePudding user response:
You can create a generic class that takes the type parameter for the FailsafeExecutor and use that to initialize the object. Here's an example:
public class FailsafeHelper<R> {
private final FailsafeExecutor<R> executor;
public FailsafeHelper(P outerPolicy, P... policies, Scheduler scheduler) {
this.executor = Failsafe.with(Collections.singletonList(outerPolicy), policies)
.with(scheduler)
.getAsyncExecution(execution -> doSomething(x, y));
}
public R execute() {
return this.executor.execute();
}
}
You can then use this class as follows:
FailsafeHelper<R> failsafeHelper = new FailsafeHelper<R>(retryPolicy, scheduler);
R result = failsafeHelper.execute();
This way, you can create a single FailsafeHelper object and reuse it to execute the FailsafeExecutor multiple times.
CodePudding user response:
Yes, you are correct. My suggestion would move the creation of the FailsafeExecutor to the FailsafeHelper class, but you would still need to create a new instance of the FailsafeHelper on each execution.
However, you could also consider using a Singleton pattern for the FailsafeHelper class, which would allow you to reuse the same instance of the FailsafeExecutor across multiple executions. This way, you would only have to create the FailsafeExecutor once, and it would be available for use in any subsequent executions.
Here is an example of how the FailsafeHelper class could be implemented using the Singleton pattern:
public class FailsafeHelper {
// Private constructor to prevent instantiation
private FailsafeHelper() {}
// Static instance of the FailsafeHelper class
private static final FailsafeHelper INSTANCE = new FailsafeHelper();
// Static FailsafeExecutor instance
private final FailsafeExecutor<?> executor = Failsafe.with(Collections.singletonList(retryPolicy))
.with(scheduler)
.<R>getAsyncExecution(execution -> doSomething(x, y));
// Public static method to get the instance of the FailsafeHelper class
public static FailsafeHelper getInstance() {
return INSTANCE;
}
// Public method to get the FailsafeExecutor instance
public FailsafeExecutor<?> getExecutor() {
return executor;
}
}
Then, in your code, you can simply call the getInstance() method to get the single instance of the FailsafeHelper class, and use the getExecutor() method to get the FailsafeExecutor instance for use in your executions.
Here is an example of how this could be used in your code:
// Get the single instance of the FailsafeHelper class
FailsafeHelper failsafeHelper = FailsafeHelper.getInstance();
// Get the FailsafeExecutor instance from the FailsafeHelper
FailsafeExecutor<?> executor = failsafeHelper.getExecutor();
// Use the FailsafeExecutor to execute your operation
var result = executor.<R>getAsyncExecution(execution -> doSomething(x, y));
I hope this helps!