This post series assumes familiarity with Kotlin, Java, and Spring Boot.
No AI was used during the writing of this post series.
CoroutineScope vs StructuredTaskScope: Which one to choose?
Let's summarize what it took to build both solutions:
CoroutineScope
- We had to add 2 libraries
val coroutinesVersion = "1.10.2"
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:$coroutinesVersion")
- We had to use
runBlocking - We had to change the dispatcher (we used
Dispatchers.IO) - We had to wrap blocking calls in
runInterruptible - We had to pass
MDCContext()torunBlocking
StructuredTaskScope
- No libraries added, just JDK 25
- We had to remember to call
join - We had to build some helpers/wrappers to make it smooth:
taskScopeinstead ofStructuredTaskScope.open<Any>.use - We had to manually propagate MDC in our wrapper or to explore
ScopedValuefor this use case
When to use CoroutineScope and why?
- Coroutines are, just like Kotlin, very flexible. If our use case involved manual cancellation of subtasks or some more complex concurrency patterns, coroutines and the ecosystem can probably handle it.
- If our entire system is non-blocking, using a reactive framework and libraries, then coroutines are the right tool. They will make the code much more readable and less error prone.
When to NOT use CoroutineScope and why?
- Coroutines are invasive. The
suspendkeyword will spread through the codebase like a virus. If the entire system is blocking, introducing coroutines may be disruptive and may take extra care to cover all the edge cases. - If everything is already blocking it's better to make blocking less expensive (by using virtual threads), than to replace it with non-blocking.
- If stack traces and debugging are very important
When to use StructuredTaskScope
- If we use Java, there is no alternative.
- If everything is already blocking.
- If we don't mind that it's a preview API.
- If we are tired from untangling reactive/non-blocking stack traces
- If we want debugging to be easy
When NOT to use StructuredTaskScope
- When preview features are too scary for us
- When we already have a codebase using reactive/non-blocking code
Conclusion
Both are great, one is old, the other is new, and just like Kotlin and Java, they will continue to learn from each other as they develop further.
Top comments (0)