SuspendApp: A New Arrow Library
by Simon Vergauwen
- •
- August 16, 2022
- •
- arrow• kotlin• functional programming
- |
- 3 minutes to read.

There is a new library in the Arrow ecosystem, and its only base dependency is KotlinX Coroutines.
SuspendApp
offers an application builder that gives strong guarantees in terms of application termination. It enables you to reason about Resource safety in terms of Structured Concurrency, which allows us to safely compose suspend fun
. When building applications with such requirements, it typically requires us to write a lot of platform-specific code. This library aims to solve that problem by leveraging Kotlin MPP.
Setting up SuspendApp with Gradle is quite easy. Simply add the following coordinates to your dependencies
block, io.arrow-kt:suspendapp:0.3.0
. It’ll automatically pull in the correct dependency depending on the configured target platforms. Full documentation can be found on the project website.
An example SuspendApp
Once the dependency is in, bringing the safety guarantees is as simple as wrapping the entire main
with SuspendApp
. Let’s discuss with a concrete example, which are those guarantees:
fun main() = SuspendApp {
try {
println("App Started! Waiting until asked to shutdown.")
while (true) {
delay(2_500)
println("Ping")
}
} catch (e: CancellationException) {
println("Cleaning up App... will take 10 seconds...")
withContext(NonCancellable) { delay(10_000) }
println("Done cleaning up. Will release app to exit")
}
}
When you run this example, it will:
- print “App Started! Waiting until asked to shutdown.”
- Loop until
SuspendApp
gets cancelled, and it’ll print “Ping” every 2,5 seconds. - Upon cancellation it will:
- print “Cleaning up App… will take 10 seconds…”
- Delay for 10 seconds
- print “Done cleaning up. Will release app to exit”
To build
and run this example, we should just build the binaries and execute them.
For example for MacOs
and NodeJS
.
./gradlew build
build/bin/macosX64/releaseExecutable/example.kexe
node build/compileSync/main/productionExecutable/kotlin/suspendapp-example.js
After running the binary, we’ll see the following getting printed:
App Started! Waiting until asked to shutdown.
Ping
Ping
When we press CTRL+c
(SIGINT
), we’ll see the application shutting down.
^CCleaning up App... will take 10 seconds...
Done cleaning up. Will release app to exit
In this example, the cleaning has been simulated by a 10 second delay. This is not an unrealistic scenario; for example, in the docs, we cover the case of a Ktor application that must support graceful shutdown when managed by Kubernetes.
SuspendApp vs runBlocking
KotlinX Coroutines offers us runBlocking
out-of-the-box for native
and JVM
platforms, but not for js
.
SuspendApp
is available for native
, JVM
, and js
(node), so it allows you to define an application within commonMain
for these targets.
Additionally, if we replace SuspendApp
with runBlocking
in the above example, the clean-up steps never execute.
App Started! Waiting until asked to shutdown.
Ping
Ping
^C
The clean-up steps never execute because runBlocking
is not taking into account termination events from the platforms. runBlocking
doesn’t wait for cancellation or resource clean-up and simply shuts down the process upon all termination events. Instead, SuspendApp
builds on top of runBlocking
and observes termination events from the platform awaiting cancellation, resource clean-up, and following the rules of structured concurrency.
Conclusion
Reason about resource safety in the same way you reason about Structured Concurrency with SuspendApp!
SuspendApp gives strong guarantees about resource-safety
, and structured concurrency supporting a Kotlin Multiplatform commonMain
application entry-point.
If you have any feedback or suggestions, please share them in the #arrow channel on KotlinLang Slack or the Github Repository.