- the suspend fun may return COROUTINE_SUSPENDED
- Spring AOP needs to filter COROUTINE_SUSPENDED because the fun did not actually return
Comment From: sdeleuze
Seems to be a pre-requisite for #23575. Good candidate for Spring Framework 5.3.
Comment From: mkopylec
I need this feature badly :)
Comment From: zymen
Hi, also highly requested!
Comment From: wrotycz
Yeah, that would help a lot!
Comment From: faderskd
Need this feature too !
Comment From: gwieczorek-it
Hi, I would love to see this feature implemented.
Comment From: rudykocur
Sadly stumbled upon this bug :( I would need that badly
Comment From: sdeleuze
Hey, here is an update on that topic. I have added @Transactional
support for Coroutines via https://github.com/spring-projects/spring-framework/commit/5429c7afebaa3255ea80197224023c29c7d552ec and I have provided some guidance on Spring Security side for similar support.
Those Spring Data and Spring Security supports are possible without any change on Spring AOP, and Coroutines support requires to be added at a Reactive-aware level which is not the case of Spring AOP if I am not mistakes, so I am not sure anymore this issue is relevant.
With this progresses in mind, please share your use cases requiring an update on Spring AOP if any.
Comment From: sdeleuze
I created this draft commit to add Coroutines support for Spring AOP, it is pretty straightforward by itself but I am not yet convinced we should integrate it in 5.3 because:
- It will require special handling of the Reactive return value in most cases (Spring Security)
- We don't have yet other use cases where it would just work, since @Validated
support (#23499) is blocked on Hibernate Validator support and even in that use case support could be added in MethodValidationInterceptor
.
Comment From: RobertHeim
Any updates?
Comment From: gs-husam
Just hit this as well trying to add @Transactional
to suspend functions, would be very helpful to have!
Has anyone found a workaround for @Transactional
, apart from wrapping the code in explicit reactive transaction operator blocks?
Comment From: sdeleuze
As documented here:
Transactions on Coroutines are supported via the programmatic variant of the Reactive transaction management provided as of Spring Framework 5.2.
Thread-bound transactions are not supported.
Comment From: mkopylec
When it is planned to be done?
Comment From: mkopylec
Here is a sample of how it can be done. Haven't checked it but looks promising.
Comment From: renatomrcosta
Hi, just noticed this issue when working with @Timed / @NewSpan annotations for Micrometer's TimedAspect and @NewSpan in Sleuth. In both cases, the measurements are erroneously finished at the first suspension point.
Looking forward to updates on this issue as well, and a big thanks to everyone doing work on it!
Comment From: jzheaux
Spring Security needs this in order to support method security in co-routines. The existing method interceptor, PrePostAdviceMethodInterceptor
, uses CoroutineUtils.invokeSuspendFunction
; however, this has the notable downside of skipping downstream method interceptors.
Comment From: akhilpratap1991
Here is a sample of how it can be done. Haven't checked it but looks promising.
Anyone able to make this work? I am getting into infinite loop
Comment From: sdeleuze
We were able to leverage Spring AOP + Coroutines in #29527 via the invocation of MonoKt.awaitSingleOrNull
with explicit passing of the contination here.
@jzheaux Could you check if this kind of solution is possible on your Spring Security use case? If yes, we can maybe explore if a generic handling of Coroutines with Spring AOP is possible.
Comment From: andydenk
Is this expected to be addressed for Spring 5.3.x / 5.x.x as well?
I am facing this issue and it keeps me from introducing AOP advice to properly trace suspend functions and functions returning flow as OpenTelemetry also seems to lack proper support for coroutines.
Comment From: sdeleuze
No, this is unlikely to be fixed on Spring Framework 5.x.
@jzheaux Could you please provide me your feedback on this comment?
Comment From: nenros
I would ask if there is chance to fix it at all? Issue is really old and there isn't any visible progress here.
Comment From: sdeleuze
This is a tricky one from a design perspective, but let see if we can move forward. I will reach Spring Security team to try to get a feedback.
Comment From: RobertHeim
any updates? seems to block a lot of other issues downstream
Comment From: jun-wu-tw
any updates? seems to block a lot of other issues downstream
Hey, RoberHeim. I find a workaround for coroutine with Aspectj, but I don't remember the link. You can refer to the following code. Hope it can help you out. 🙏
- Add the extensions
val ProceedingJoinPoint.coroutineContinuation: Continuation<Any?>
get() = this.args.last() as Continuation<Any?>
val ProceedingJoinPoint.coroutineArgs: Array<Any?>
get() = this.args.sliceArray(0 until this.args.size - 1)
suspend fun ProceedingJoinPoint.proceedCoroutine(
args: Array<Any?> = this.coroutineArgs
): Any? = suspendCoroutineUninterceptedOrReturn { continuation ->
this.proceed(args + continuation)
}
fun ProceedingJoinPoint.runCoroutine(
block: suspend () -> Any?
): Any? =
block.startCoroutineUninterceptedOrReturn(this.coroutineContinuation)
- Add the Continuation point cut
@Pointcut("args(.., kotlin.coroutines.Continuation)")
fun suspendFunctionPointCut() {
}
- Usage (combine your personal with Continuation point cut)
@Around("YourCustomPointCut() && suspendFunctionPointCut()")
fun handleGenericSystemErrors(joinPoint: ProceedingJoinPoint): Any? {
return joinPoint.runCoroutine {
val result = joinPoint.proceedCoroutine()!!
return@runCoroutine result
}
}
Comment From: RobertHeim
@jun-wu-tw the problem is not that we need it in our code base, but it must be integrated in spring itself to solve downstream issues:
- https://github.com/spring-projects/spring-security/issues/12080
- https://github.com/spring-projects/spring-security/issues/12821 and esp. this comment
Comment From: sdeleuze
After working on the Spring Security repro created by @jzheaux, I may have found a potential way to handle this.
I managed to fix the repro with some changes on Spring Framework side that you can see in this draft commit. In a nutshell, at InvocableHandlerMethod
level, when a proxified suspending function is detected, we just invoke the regular Java code path with method.invoke(getBean(), args)
and defer the invocation of CoroutinesUtils#invokeSuspendingFunction
to org.springframework.aop.support.AopUtils#invokeJoinpointUsingReflection
.
That way, proxified suspending functions return their Mono
counterpart, allowing MethodInterceptor
s to deal with those like if it was reactive methods returning Mono
. This slightly changes how Coroutines interceptors work, but they were broken for a lot of use cases and I think this also makes them more consistent with the rest of the Coroutines support in Spring.
It is possible to test this Spring Framework branch by cloning it, running ./gradlew publishToMavenLocal
and then using this repro branch that should now work correctly.
As a consequence, I tentatively plan resolving this issue in Spring Framework 6.1.0-RC1
. Since a lot of Spring developers are waiting for the resolution of this issue, please provide your feedback on this proposal if possible.
@jhoeller @rstoyanchev @poutsma @jzheaux Please let me know if you have any concern about the proposed solution.
Comment From: sdeleuze
Looks like we are going to have to do something more evolved in order to support non reflective use cases and make this less intrusive from the caller perspective.
Comment From: sdeleuze
Initial support pushed, please test Spring Framework 6.1.0-SNAPSHOT
and let me know how it goes.
@jzheaux Please let me know how it goes on Spring Security after you refine the support to avoid the multiple subscription issues we discussed on your repro.
@mp911de @rstoyanchev I refined reactive transactional and HTTP service interface support to leverage those generic capabilities, tests are green but please ping me if you see related reports on Coroutines support.
Comment From: tonnoz
@jun-wu-tw sir, you saved the day, thank you so much