New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
@TimeLimiter times out slow method but does not cancel running future #905
Comments
This blog post explains it quite well: This flag only works when you use TimeLimiter to decorate a method which returns a Future. But unfortunately Futures are not yet supported via annotations/aspects, but only via the functional style. |
Is there a code example for this? This did not work for me, the Thread was not interrupted: public Callable<List<String>> getAll() {
TimeLimiterConfig config = TimeLimiterConfig.custom().cancelRunningFuture(true).timeoutDuration(Duration.ofMillis(1000)).build();
TimeLimiterRegistry timeLimiterRegistry = TimeLimiterRegistry.of(config);
ExecutorService executor = Executors.newSingleThreadExecutor();
return timeLimiterRegistry.timeLimiter("getAll").decorateFutureSupplier(() -> executor.submit(() -> repository.getAll()));
} |
@RobWin I'm trying to understand this, but I struggle with the following:
So what return-type do I need for the @TimeLimiter-Annotation to work as expected (cancel running execution and throw TimeoutException)? We had a running functional implementation, but we are trying to switch away from this to an annotation-based style. Simply because we want to get rid of the gluecode (decorating suppliers...). |
You can use a TimeLimiter to decorate a method which returns a |
@RobWin thanks for clarifying. Just to make sure I understood you correctly: |
No, TimeLimiter (TimeLimiterAspect) still throws a TimeoutException. See our Spring Boot 2 demo. The TimeLimiter also works for all reactive types from Spring Reactor or RxJava2 and RxJava3 |
Ah alright, now I get it. Thank you. The TimeoutException is thrown, but the CompletableFuture is still running. In this case: would you expect a Example: @TimeLimiter(name="myName")
@Retry(name="myName)
public CompletableFuture<String> myFuncition() {...} |
Yes, check out our demo: You can add a |
Hello! Thank you for explanation for this issue. I'd like to clarify my understanding. I need to use a ThreadPoolBulkhead combined with CircuitBreaker and TimeLimiter, something like example from docs
So, in this case (because of CompletableFuture) I cannot use interrupting of ThreadPoolBulkhead's thread by timeout. Is there some way to use ThreadPoolBulkhead + TimeLimiter with ability to interrupt a thread, for example using ThreadPoolBulkhead with simple Future instead of CompletableFuture? As I know I could do it in hystrix. It needed to prevent threads from freezing for a long time when many timeouts occur |
Unfortunately the ThreadPoolBulkhead always returns a CompletionStage backed by a CompletableFuture.
|
OK, thank you. Are there some plans to support it in thread pool bulhkead in future for compatibility of migrating from hystrix? |
No, currently there are no plans to support Future since blocking code should be prevented. |
OK, if I understand correctly, to use TimeLimiter with interruptable thread pool I can use ExecutorService instead of ThreadPoolBulkhead with almost same features (core threads, max threads, keepAliveTime, intercepting cases when there are no free workers), and I have to implement getting thread pool by name using ConcurrentHashMap directly instead of ThreadPoolBulkheadRegistry? |
If you like you can try to create a PR and add a Shouldn't be too complicated and then we can support ThreadPoolBulkhead and Timelimiter. |
@RobWin |
Resilience4j version:
1.3.1
Java version:
1.8.0_241
Spring Boot version:
2.2.5.RELEASE
If a method has the
@TimeLimiter
annotation added that references a time limiter configured withcancelRunningFuture: true
then, when a timeout event successfully occurs, the currently runningCompleteableFuture
does not appear to be cancelled. Instead it just keeps on running.In the below set up the slow method being called from the protected method just sleeps for 30 seconds and then writes a message to announce it has woken up. This is deliberately being done to try and simulate a very slow/hung method.
application.yml
SlowService.java
MyController.java
The presence of the
@TimeLimiter
annotation on the slowHandler() method above ensures that requests to it time out after 5000ms (just as configured for the mytimelimiter instance in the application.yml values). Perfect. However, after another 25 seconds or so the slowMethod() logs that it has woken up and then can presumably carry on going about its work. That seems to indicate that the future was not cancelled when the time out successfully occurred on the calling method.Is the above working as expected? Perhaps it is the case that
resilience4j.timelimiter.instances.{name}.cancelRunningFuture
is not expected to have any effect when the time limiter is referenced from a@TimeLimiter
annotation? Alternatively, maybe my calling method decorated with the annotation needs to be rewritten in order to enable the cancelling of theCompleteableFuture
?The text was updated successfully, but these errors were encountered: