This is an example of using coroutines with Spring MVC (not webflux!)
DemoController
uses https://github.com/joost-de-vries/spring-coroutine, but since that library was published to bintray, I copied the class SpringCoroutineScope
and dependencies here.
The /boomerang/{x} endpoint waits for x
seconds and then returns x
back. If x
is 0 then it throws an exception.
Looking at the implementation I suspected that, by reusing the same scope instance in a Spring bean, if one of the requests fails it would cancel the parent job and other parallel or subsequent requests would also fail.
This can be reproduced by changing back:
@Suppress("FunctionName")
fun SpringScope(dispatcher: CoroutineDispatcher = Dispatchers.Default, job: Job = SupervisorJob()): SpringScope =
SpringScope(dispatcher + job)
to
@Suppress("FunctionName")
fun SpringScope(dispatcher: CoroutineDispatcher = Dispatchers.Default, job: Job = Job()): SpringScope =
SpringScope(dispatcher + job)
Obviously, using a SupervisorJob
fixes this.
Here is a use case that reproduces the aforementioned problem:
#running the app:
./gradlew clean run
#let's do some requests
curl http://localhost:8080/boomerang/1
curl http://localhost:8080/boomerang/10
#if we call it in less than 10 seconds, the previous request will also fail
curl http://localhost:8080/boomerang/0
#this also fails
curl http://localhost:8080/boomerang/10