CircuitBreakerAction
contain some boilerplate that can be encapsulated in a single interface.
Also, consistent error handling could be enforced - now these things may occur:
handler gets called by a future that succeeds
handler gets called by a future that fails
handler never gets called as future never resolves
handler never gets called as action throws an exception
handler gets called with AsyncResult that is not resolved at the time of reading value (see Vert.x bug)
Describe the solution you'd like
Create AsyncFragmentOperation interface
package io.knotx.fragments.api;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
public interface AsyncFragmentOperation extends FragmentOperation {
@Override
default void apply(FragmentContext fragmentContext, Handler<AsyncResult<FragmentResult>> resultHandler) {
tryApply(fragmentContext).onComplete(resultHandler);
}
default Future<FragmentResult> tryApply(FragmentContext fragmentContext) {
try {
Future<FragmentResult> result = apply(fragmentContext);
if (result != null) {
return result;
} else {
return Future.failedFuture(
new IllegalStateException("Action " + this.getClass().getName()
+ " returned null Future. Created failed Future to pass information to handler.")
);
}
} catch (Throwable t) {
return Future.failedFuture(t);
}
}
Future<FragmentResult> apply(FragmentContext fragmentContext);
}
With the following semantics:
Handler is always called (unless underlying action halts)
If action successfully returns a non-null Future<FragmentResult>, then handler is called with it
If action returns null or throws an exception, handler is called with Future.failedFuture(reason).
Unfortunatelly, failed future in this case encapsulates all three cases (failure within action, null result and exception thrown from action). However, each time we're dealing with an exception so I believe this is not an issue and can simplify error handling in the whole knotx-fragments repository.
Is your feature request related to a problem? Please describe. Library actions that are asynchronous:
HttpAction
InMemoryCacheAction
CircuitBreakerAction
contain some boilerplate that can be encapsulated in a single interface.Also, consistent error handling could be enforced - now these things may occur:
Describe the solution you'd like
Create
AsyncFragmentOperation
interfaceWith the following semantics:
Future<FragmentResult>
, then handler is called with itFuture.failedFuture(reason)
.Unfortunatelly, failed future in this case encapsulates all three cases (failure within action, null result and exception thrown from action). However, each time we're dealing with an exception so I believe this is not an issue and can simplify error handling in the whole knotx-fragments repository.
Describe alternatives you've considered N/A
Additional context Relates to #184