DEV Community

Cover image for Structured Concurrency in Practice: CoroutineScope vs StructuredTaskScope [Part 5]
Filip Egeric
Filip Egeric

Posted on

Structured Concurrency in Practice: CoroutineScope vs StructuredTaskScope [Part 5]

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

  1. 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")
Enter fullscreen mode Exit fullscreen mode
  1. We had to use runBlocking
  2. We had to change the dispatcher (we used Dispatchers.IO)
  3. We had to wrap blocking calls in runInterruptible
  4. We had to pass MDCContext() to runBlocking

StructuredTaskScope

  1. No libraries added, just JDK 25
  2. We had to remember to call join
  3. We had to build some helpers/wrappers to make it smooth: taskScope instead of StructuredTaskScope.open<Any>.use
  4. We had to manually propagate MDC in our wrapper or to explore ScopedValue for this use case

When to use CoroutineScope and why?

  1. 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.
  2. 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?

  1. Coroutines are invasive. The suspend keyword 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.
  2. If everything is already blocking it's better to make blocking less expensive (by using virtual threads), than to replace it with non-blocking.
  3. If stack traces and debugging are very important

When to use StructuredTaskScope

  1. If we use Java, there is no alternative.
  2. If everything is already blocking.
  3. If we don't mind that it's a preview API.
  4. If we are tired from untangling reactive/non-blocking stack traces
  5. If we want debugging to be easy

When NOT to use StructuredTaskScope

  1. When preview features are too scary for us
  2. 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)