https://kotlinlang.org logo
Title
n

Nikky

02/27/2022, 12:22 PM
in kotlin-native .. what is the correct way to start ktor so that i can shut it down from a signal handler? seems like doing
server.start(wait = true)
will just block my application completely when i call
server.stop(500, 500)
not sure why.. could it be that joining the jobs is blocking ? for now i am using this..
server = embeddedServer(...)

server.start(wait = false)

while (true) {
    sleep(1)
}
and in the signal handler i call
server.stop(500, 500)
if anybody knows a cleaner solution.. would like to make this work better i also noticed.. if i use
delay
instead of sleep it will also continue to block..?
h

hfhbd

02/27/2022, 12:32 PM
What about using coroutines?
coroutineScope {
  val server = embeddedServer(..)
  server.start(wait = false)

  action()
  server.stop()
}

suspend fun action() = suspendCoroutine { cont ->
  registerSignalHandler(callback = {
    cont.resume()
  })
}
n

Nikky

02/27/2022, 2:57 PM
this works nicely if i understand this correctly it stops at the end of
suspendCoroutine
until the signal handler triggers the continuation ?
h

hfhbd

02/27/2022, 3:30 PM
Yes
e

ephemient

02/27/2022, 5:13 PM
IMO it would be safer to use a semaphore,
val stopSignal = Semaphore(1, 1)
registerSignalHandler { stopSignal.release() }
coroutineScope {
    ...
    stopSignal.acquire()
}
note that in both solutions, your program will crash if the signal handler is invoked multiple times. you can use a
CompletableDeferred
instead if that is a concern
n

Nikky

02/27/2022, 5:44 PM
upon some more experimenting i found this solution..
val completableJob = SupervisorJob()
SignalHandler.onSignal(SIGINT) { _, signalName ->
    logger.warn { "received signal $signalName, stopping server.." }
    // completableJob.complete() // this will cause it to hang
    completableJob.cancel()
}
embeddedServer(
    factory = CIO,
    host = serverOptions.host,
    port = serverOptions.port,
    logger = KtorKLogger(),
    parentCoroutineContext = completableJob
) {
    configureHTTP()
    configureRouting()
}.start(true)
on a sidenote.. ith all these solutions there seems to be the problem that after the interrupt.. any
println
or logging calls seem to disappear might be a problem caused by interrupting.. i wonder.. what mistake i am overlooking.. PS: found that using cancel will work..
but i really like the solution using a
CompletableDeferred
too