Affects: spring-webflux 5.3.7
I write my filter, pass some parameters to coroutine context via witchContext
and want to be able use it later in the child coroutines and handlers. The problem is that CoroutineContext
is lost in filter chain.
For example something like this
@Bean
fun testRouter(tracingFilter: ITracingFilter) = coRouter {
GET("/test") { request ->
val span = coroutineContext[SpanContext] // is null
someHandler.processRequest()
}
filter{ serverRequest, suspendFunction ->
withContext(SpanContext()) {
suspendFunction.invoke(serverRequest)
}
}
}
Comment From: emrearslan
Is there any progress on this?
Comment From: sdeleuze
I can confirm the issue which seems to impact CoWebFilter
as well on annotation-based programming model side cc @poutsma .
During filter + handler Coroutines use case, the handler should reuse the context defined by the filter and currently, it overrides it with Dispatchers.Unconfined
when invoking the mono(Dispatchers.Unconfined) { }
lambda at handler level. Using mono(Dispatchers.Unconfined)
is ok when this is the "top level Coroutines invokation", but not when this is a handler 'nested' in a filter.
I guess the handler should reuse filter CoroutineContext
when defined, but not sure yet how.
Comment From: sdeleuze
See potentially related issue #27522.
Comment From: sdeleuze
Looks like I have found a way to propagate correctly the CoroutineContext
by introducing a HandlerFunction
implementation that allows to pass explicitly the context:
abstract class ContextAwareHandlerFunction<T : ServerResponse> : HandlerFunction<T> {
override fun handle(request: ServerRequest): Mono<T> {
return handle(Dispatchers.Unconfined, request)
}
abstract fun handle(context: CoroutineContext, request: ServerRequest): Mono<T>
}
More details in this draft commit, feedback welcome.
Comment From: IevgenBizz
Hello @sdeleuze Thanks for your changes. I have related question: In our application we are using webflux and our controllers annotated with @GetMapping annotation. If I'm right you changes won't be applied for this case. There are used org.springframework.web.reactive.result.method.InvocableHandlerMethod#invoke
if (isSuspendingFunction) {
value = CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);
}
else {
value = method.invoke(getBean(), args);
}
Do you have any ideas how I can pass MDCContext() to suspended controller function, when MDC was set in CoWebFilter? (I found related thread https://github.com/spring-projects/spring-framework/issues/27522)
Comment From: sdeleuze
With Spring Boot 3.2 + Spring Framework 6.1, I think that should be the case, if not please create an issue with a minimal reproducer as an attached project or a link to a repository.