-
Notifications
You must be signed in to change notification settings - Fork 455
/
Copy pathSuspendApp.kt
56 lines (53 loc) · 1.94 KB
/
SuspendApp.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package arrow.continuations
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.time.Duration
import kotlinx.coroutines.*
/**
* An unsafe blocking edge that wires the [CoroutineScope] (and structured concurrency) to the
* [SuspendApp], such that the [CoroutineScope] gets cancelled when the `App` is requested to
* gracefully shutdown. => `SIGTERM` & `SIGINT` on Native & NodeJS and a ShutdownHook for JVM.
*
* It applies backpressure to the process such that they can gracefully shutdown.
*
* @param context the [CoroutineContext] where [block] will execute. Use [EmptyCoroutineContext] to
* create an `CoroutineDispatcher` for the main thread and run there instead.
* @param timeout the maximum backpressure time that can be applied to the process. This emulates a
* `SIGKILL` command, and after the [timeout] is passed the App will forcefully shut down
* regardless of finalizers.
* @param block the lambda of the actual application.
*/
@OptIn(ExperimentalStdlibApi::class)
public fun SuspendApp(
context: CoroutineContext = Dispatchers.Default,
uncaught: (Throwable) -> Unit = Throwable::printStackTrace,
timeout: Duration = Duration.INFINITE,
process: Process = process(),
block: suspend CoroutineScope.() -> Unit,
): Unit =
process.use { env ->
env.runScope(context) {
val job =
launch(start = CoroutineStart.LAZY) {
try {
block()
env.exit(0)
} catch (_: SuspendAppShutdown) {} catch (e: Throwable) {
uncaught(e)
env.exit(-1)
}
}
val unregister =
env.onShutdown {
withTimeout(timeout) {
job.cancel(SuspendAppShutdown)
job.join()
}
}
job.start()
job.join()
unregister()
}
}
/** Marker type so track shutdown signal */
private object SuspendAppShutdown : CancellationException("SuspendApp shutting down.")