jooby
jooby copied to clipboard
In case of async route handlers, after() runs before the handler, not after it
Example with Kotlin coroutines:
before {
println("Before handler")
ctx.onComplete {
println("After response sent")
}
}
after {
println("After normal handler, but BEFORE suspend handler")
}
coroutine {
get("/") {
println("After already executed at this point")
"Hello"
}
}
There is a workaround to use onComplete
, but it runs after the response has been sent and in a different thread.
The same problem is also with e.g. returning a CompletableFuture
from Java route handler, and probably others that use DetachHandler
.
Yea, non-blocking types don't work well with filters. It is documented here: https://jooby.io/#responses-nonblocking-limitations
@jknack with Kotlin coroutines it would be easy to guarantee the execution pipeline.
Otheriwse, it's hard to control things like transactions. The transaction handling example in the docs don't work with async requests at all. Probably you should add there an info that global transaction handling is not possible for non-blocking requests currently...
I tried putting transaction handling into onComplete(), but there are problems with it:
- Transaction is closed (committed/rolledback) after the response is sent, therefore it is possible for the subsequent request to "see" old DB state.
- In case of errors and rollback, again, you cannot unsend the response.
I tried looking at CoroutineLauncher and see if filters could be run there, but the current routing model doesn't allow for it easily...
I want to revisit and see if we can improve it. Ideally, would like do the same for completable future
@cbxp @angryziber how do you share ThreadLocal between coroutine scope?