Skip to content
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

java.lang.ClassCastException when using @Retryable with coroutine #4438

Closed
xiscosc opened this issue Nov 5, 2020 · 11 comments
Closed

java.lang.ClassCastException when using @Retryable with coroutine #4438

xiscosc opened this issue Nov 5, 2020 · 11 comments
Assignees
Labels
lang: kotlin Issues or features specific to Kotlin status: awaiting third-party Awaiting changes to a third party library
Milestone

Comments

@xiscosc
Copy link
Contributor

xiscosc commented Nov 5, 2020

@Retryable annotation is not working well with Kotlin coroutines. It does its work when some error is thrown but it fails when it's trying to return the correct value. I found two kind of errors:

  1. java.lang.IllegalStateException: Not a Kotlin coroutine
  2. java.lang.ClassCastException: class io.micronaut.aop.util.CompletableFutureContinuation cannot be cast to class kotlin.coroutines.jvm.internal.CoroutineStackFrame (io.micronaut.aop.util.CompletableFutureContinuation and kotlin.coroutines.jvm.internal.CoroutineStackFrame are in unnamed module of loader 'app')

I created a project with several tests in order to reproduce them, it can be found here https://github.com/xiscosc/micronaut-kotlin-retry-coroutines

Steps to Reproduce

Not a Kotlin coroutine error

  1. Create a class with @Retryable and a method that returns from a coroutine
@Singleton
@Retryable(attempts = "1")
class HomeService {
    suspend fun test2(): String {
        return coroutineScope {
            "hi"
        }
    }
}
  1. Call the method
@Controller("/home")
class HomeController(val homeService: HomeService) {

    @Get
    suspend fun getTest2(): HttpResponse<String> {
        return HttpResponse.ok(homeService.test2())
    }
}

Cast error

  1. Create a class with @Retryable and a method that returns from a coroutine with a delay
@Singleton
@Retryable(attempts = "1")
class HomeService {
    suspend fun test2(): String {
        return coroutineScope {
           delay(1L)
            "hi"
        }
    }
}
  1. Call the method
@Controller("/home")
class HomeController(val homeService: HomeService) {

    @Get
    suspend fun getTest2(): HttpResponse<String> {
        return HttpResponse.ok(homeService.test2())
    }
}

Expected Behaviour

Method test2() should return string "hi"

Actual Behaviour

Not a Kotlin coroutine error

java.lang.IllegalStateException: Not a Kotlin coroutine
	at io.micronaut.aop.internal.intercepted.KotlinInterceptedMethod.interceptResultAsCompletionStage(KotlinInterceptedMethod.java:126)
	at io.micronaut.aop.internal.intercepted.KotlinInterceptedMethod.interceptResult(KotlinInterceptedMethod.java:138)
	at io.micronaut.retry.intercept.DefaultRetryInterceptor.retrySync(DefaultRetryInterceptor.java:214)
	at io.micronaut.retry.intercept.DefaultRetryInterceptor.intercept(DefaultRetryInterceptor.java:119)
	at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:82)
	at com.example.controllers.$HomeServiceDefinition$Intercepted.test2(Unknown Source)
	at com.example.controllers.HomeController.getTest2(HomeController.kt:26)
	at com.example.controllers.$HomeControllerDefinition$$exec2.invokeInternal(Unknown Source)
	at io.micronaut.context.AbstractExecutableMethod.invoke(AbstractExecutableMethod.java:146)
	at io.micronaut.context.DefaultBeanContext$4.invoke(DefaultBeanContext.java:474)
	at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:312)
	at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:118)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildResultEmitter$10(RoutingInBoundHandler.java:1363)
	at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:35)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.http.server.context.ServerRequestContextFilter.lambda$doFilter$0(ServerRequestContextFilter.java:62)
	at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14868)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildExecutableRoute$6(RoutingInBoundHandler.java:1068)
	at io.micronaut.web.router.DefaultUriRouteMatch$1.execute(DefaultUriRouteMatch.java:80)
	at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:118)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.handleRouteMatch(RoutingInBoundHandler.java:693)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:549)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:144)
	at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:102)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:197)
	at io.micronaut.http.netty.stream.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:121)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
	at io.netty.handler.codec.http.HttpServerKeepAliveHandler.channelRead(HttpServerKeepAliveHandler.java:64)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.flow.FlowControlHandler.dequeue(FlowControlHandler.java:200)
	at io.netty.handler.flow.FlowControlHandler.channelRead(FlowControlHandler.java:162)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:834)

Cast error

Exception in thread "kotlinx.coroutines.DefaultExecutor" java.lang.ClassCastException: class io.micronaut.aop.util.CompletableFutureContinuation cannot be cast to class kotlin.coroutines.jvm.internal.CoroutineStackFrame (io.micronaut.aop.util.CompletableFutureContinuation and kotlin.coroutines.jvm.internal.CoroutineStackFrame are in unnamed module of loader 'app')
	at kotlinx.coroutines.internal.ScopeCoroutine.getCallerFrame(Scopes.kt:19)
	at kotlinx.coroutines.debug.internal.DebugProbesImpl.owner(DebugProbesImpl.kt:394)
	at kotlinx.coroutines.debug.internal.DebugProbesImpl.updateRunningState(DebugProbesImpl.kt:369)
	at kotlinx.coroutines.debug.internal.DebugProbesImpl.updateState(DebugProbesImpl.kt:351)
	at kotlinx.coroutines.debug.internal.DebugProbesImpl.probeCoroutineResumed$kotlinx_coroutines_core(DebugProbesImpl.kt:342)
	at kotlin.coroutines.jvm.internal.DebugProbesKt.probeCoroutineResumed(DebugProbes.kt:12)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:28)
	at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:178)
	at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
	at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:362)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:396)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:388)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:484)
	at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:489)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
	at kotlinx.coroutines.DefaultExecutor.run(DefaultExecutor.kt:69)
	at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "default-nioEventLoopGroup-1-3" kotlinx.coroutines.CompletionHandlerException: Exception in completion handler ChildContinuation[CancellableContinuation(Continuation at com.example.controllers.HomeService$test1$2.invokeSuspend(HomeController.kt:58)@724814ea){CancelledContinuation[kotlinx.coroutines.JobCancellationException: ScopeCoroutine is cancelling; job=ScopeCoroutine{Cancelling}@65079ba1]}@254aad62] for ScopeCoroutine{Cancelling}@65079ba1
	at kotlinx.coroutines.JobSupport.notifyCancelling(JobSupport.kt:1516)
	at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:897)
	at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:860)
	at kotlinx.coroutines.JobSupport.makeCompletingOnce$kotlinx_coroutines_core(JobSupport.kt:825)
	at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:209)
	at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:194)
	at com.example.controllers.HomeService.test1$suspendImpl(HomeController.kt:57)
	at com.example.controllers.HomeService.test1(HomeController.kt)
	at com.example.controllers.$HomeServiceDefinition$Intercepted.$$access0(Unknown Source)
	at com.example.controllers.$HomeServiceDefinition$Intercepted$$proxy0.invokeInternal(Unknown Source)
	at io.micronaut.context.AbstractExecutableMethod.invoke(AbstractExecutableMethod.java:146)
	at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:73)
	at io.micronaut.aop.chain.InterceptorChain.proceed(InterceptorChain.java:226)
	at io.micronaut.aop.internal.intercepted.KotlinInterceptedMethod.interceptResultAsCompletionStage(KotlinInterceptedMethod.java:123)
	at io.micronaut.aop.internal.intercepted.KotlinInterceptedMethod.interceptResult(KotlinInterceptedMethod.java:138)
	at io.micronaut.retry.intercept.DefaultRetryInterceptor.retrySync(DefaultRetryInterceptor.java:214)
	at io.micronaut.retry.intercept.DefaultRetryInterceptor.intercept(DefaultRetryInterceptor.java:119)
	at io.micronaut.aop.chain.MethodInterceptorChain.proceed(MethodInterceptorChain.java:82)
	at com.example.controllers.$HomeServiceDefinition$Intercepted.test1(Unknown Source)
	at com.example.controllers.HomeController.getTest1(HomeController.kt:20)
	at com.example.controllers.$HomeControllerDefinition$$exec1.invokeInternal(Unknown Source)
	at io.micronaut.context.AbstractExecutableMethod.invoke(AbstractExecutableMethod.java:146)
	at io.micronaut.context.DefaultBeanContext$4.invoke(DefaultBeanContext.java:474)
	at io.micronaut.web.router.AbstractRouteMatch.execute(AbstractRouteMatch.java:312)
	at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:118)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildResultEmitter$10(RoutingInBoundHandler.java:1363)
	at io.reactivex.internal.operators.flowable.FlowableDefer.subscribeActual(FlowableDefer.java:35)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.http.server.context.ServerRequestContextFilter.lambda$doFilter$0(ServerRequestContextFilter.java:62)
	at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14868)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.lambda$buildExecutableRoute$6(RoutingInBoundHandler.java:1068)
	at io.micronaut.web.router.DefaultUriRouteMatch$1.execute(DefaultUriRouteMatch.java:80)
	at io.micronaut.web.router.RouteMatch.execute(RouteMatch.java:118)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.handleRouteMatch(RoutingInBoundHandler.java:693)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:549)
	at io.micronaut.http.server.netty.RoutingInBoundHandler.channelRead0(RoutingInBoundHandler.java:144)
	at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:102)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.micronaut.http.netty.stream.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:197)
	at io.micronaut.http.netty.stream.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:121)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
	at io.netty.handler.codec.MessageToMessageCodec.channelRead(MessageToMessageCodec.java:111)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:93)
	at io.netty.handler.codec.http.HttpServerKeepAliveHandler.channelRead(HttpServerKeepAliveHandler.java:64)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.flow.FlowControlHandler.dequeue(FlowControlHandler.java:200)
	at io.netty.handler.flow.FlowControlHandler.channelRead(FlowControlHandler.java:162)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:286)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.ClassCastException: class io.micronaut.aop.util.CompletableFutureContinuation cannot be cast to class kotlin.coroutines.jvm.internal.CoroutineStackFrame (io.micronaut.aop.util.CompletableFutureContinuation and kotlin.coroutines.jvm.internal.CoroutineStackFrame are in unnamed module of loader 'app')
	at kotlinx.coroutines.internal.ScopeCoroutine.getCallerFrame(Scopes.kt:19)
Caused by: java.lang.ClassCastException: class io.micronaut.aop.util.CompletableFutureContinuation cannot be cast to class kotlin.coroutines.jvm.internal.CoroutineStackFrame (io.micronaut.aop.util.CompletableFutureContinuation and kotlin.coroutines.jvm.internal.CoroutineStackFrame are in unnamed module of loader 'app')

	at kotlinx.coroutines.internal.StackTraceRecoveryKt.createStackTrace(StackTraceRecovery.kt:184)
	at kotlinx.coroutines.internal.StackTraceRecoveryKt.recoverFromStackFrame(StackTraceRecovery.kt:73)
	at kotlinx.coroutines.internal.StackTraceRecoveryKt.access$recoverFromStackFrame(StackTraceRecovery.kt:1)
	at kotlinx.coroutines.CancellableContinuationImpl.getExceptionalResult$kotlinx_coroutines_core(CancellableContinuationImpl.kt:602)

Environment Information

  • Operating System: MacOS 10.15.7 / Docker openjdk:11-slim-buster
  • Micronaut Version: 2.1.2
  • JDK Version: 11

Example Application

@graemerocher graemerocher added the lang: kotlin Issues or features specific to Kotlin label Nov 5, 2020
@jameskleeh jameskleeh self-assigned this Nov 5, 2020
@jameskleeh
Copy link
Contributor

@xiscosc I think I have a handle on the first problem, but the second is more difficult.

We need to instrument the coroutine that gets passed to the method call in order to be aware of when it completes either successfully or in error. Currently we do that by providing a custom implementation of Coroutine that has our logic in it and delegates to the original. The issue here is that Kotlin is expecting the coroutine to implement CoroutineStackFrame which is an internal class. That means we can't simply implement the interface

@dstepanov
Copy link
Contributor

Maybe the solution would be to implement KotlinInterceptedMethod in kotlin 🤔

@xiscosc
Copy link
Contributor Author

xiscosc commented Nov 9, 2020

Hey @jameskleeh, I created a PR for a possible fix of the first problem

#4453

@graemerocher graemerocher added this to the 2.1.4 milestone Nov 10, 2020
@jameskleeh jameskleeh reopened this Nov 10, 2020
@jameskleeh jameskleeh changed the title IllegalStateException: Not a Kotlin coroutine when using @Retryable java.lang.ClassCastException when using @Retryable with coroutine Nov 10, 2020
@dstepanov
Copy link
Contributor

@xiscosc I suggest you report java.lang.ClassCastException problem to https://github.com/Kotlin/kotlinx.coroutines

@timducheyne
Copy link
Contributor

@dstepanov Note that 2) is easily reproducible when you enable the coroutine debugger in IDEA

Preferences | Build, Execution, Deployment | Debugger | Data Views | Kotlin
Uncheck Disable coroutine agent

If you do that, you will get those classcast exceptions when running micronaut (eg also happens in suspended controllers)

@dstepanov
Copy link
Contributor

@timducheyne I managed to reproduce it but I think the problem is not in Micronaut but in Kotlin's coroutine implementation which shouldn't blindly cast coroutines to the internal class.

@timducheyne
Copy link
Contributor

Yes that is indeed not nice.
Ok we will file a bug in kotlinx coroutines

@willbuck
Copy link
Contributor

@timducheyne I went ahead and created the issue, I hope you don't mind. @jameskleeh and I think we have a handle on what the proper solve would be so I will be working on a PR to the coroutines library this afternoon

@timducheyne
Copy link
Contributor

@willbuck no I don't mind at all. Go ahead. I guess the fix is just use as? instead of as.
btw in case the fix in kotlin-coroutines is not ready or available,
I can also provide a fix in micronaut itself by implementing that CoroutineStackFrame
let me know if you need it, then I'll create an MR

@willbuck
Copy link
Contributor

@jameskleeh and I discussed that approach @timducheyne but I believe CoroutineStackFrame is an internal class within kotlinx.coroutines, and thus we can't implement it within Micronaut. But indeed, that was all the fix seemed to be. @timducheyne if you are able to write a test to replicate the issue within kotlinx.coroutines I imagine that'd be a great improvement to the PR to fix it, otherwise we'll see what they say!

@timducheyne
Copy link
Contributor

You're right. Implementing that internal interface is not the way to go.
Sorry, but I don't know how to best test this. Let's indeed see what they say.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lang: kotlin Issues or features specific to Kotlin status: awaiting third-party Awaiting changes to a third party library
Projects
None yet
Development

No branches or pull requests

6 participants