You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A suspend function annotated with both @Retryable and @Recoverable should retry as many times as configured in the Retryable annotation before triggering the Recoverable Fallback.
Actual Behaviour
During execution, a ClassCastException is raised during the RecoveryInterceptor that causes the Fallback to be executed during execution of the declared function.
This causes the calling function to get the 'Fallback' output before the retries are completed.
This also leads to the retries happening in the background, despite the fact that the Fallback has already fired.
The below stacktrace is logged:
java.lang.ClassCastException:classkotlin.Unit cannot be cast to class java.util.concurrent.CompletableFuture (kotlin.Unitisin unnamed module of loader 'app'; java.util.concurrent.CompletableFutureisin module java.base of loader 'bootstrap')
at io.micronaut.retry.intercept.RecoveryInterceptor.lambda$fallbackForFuture$3(RecoveryInterceptor.java:167)
at java.base/java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:859)
at java.base/java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:837)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2088)
at io.micronaut.aop.util.CompletableFutureContinuation.resumeWith(CompletableFutureContinuation.kt:51)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
Steps To Reproduce
Declare a suspend function and annotate it with both Recoverable and Retryable.
Implement a sufficient Fallback implementation for this function
Throw an exception inside the suspend function that should trigger a retry
The callers invocation of this suspend function is then 'completed' with the Fallback's return value while retries continue in the background.
My example repo has the suspend function return Unit however the same issue happens when you return a value, I tested with Boolean
Expected Behavior
A
suspend
function annotated with both@Retryable
and@Recoverable
should retry as many times as configured in theRetryable
annotation before triggering theRecoverable
Fallback.Actual Behaviour
During execution, a ClassCastException is raised during the RecoveryInterceptor that causes the Fallback to be executed during execution of the declared function.
This causes the calling function to get the 'Fallback' output before the retries are completed.
This also leads to the retries happening in the background, despite the fact that the Fallback has already fired.
The below stacktrace is logged:
Steps To Reproduce
Unit
however the same issue happens when you return a value, I tested with BooleanEnvironment Information
OS - macOS 12.2.1 (x86_64)
JVM - 11.0.11
Example Application
https://github.com/tmapes/micronaut-suspend-retry-recover
Version
3.3.4
The text was updated successfully, but these errors were encountered: