How to catch ktor server exception properly. ```su...
# ktor
v
How to catch ktor server exception properly.
Copy code
suspend fun main() {
    val scope = CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO>)

    val validServer = embeddedServer(CIO, port = 8080){}.start(false)

    val addressReuseFailureServer = scope.async(start = CoroutineStart.LAZY) {
        embeddedServer(
            factory = CIO,
            environment = applicationEngineEnvironment {
                connector { port = 8080 }
            },
            configure = { reuseAddress = false }
        ).start(wait = false)
    }
    runCatching { addressReuseFailureServer.await() }.also { println(it) }
}
when I run the above code, the line
runCatching {}
doesn't;t catch the address reuse exception, instead, it propagates and crashes the application. Could anyone help me with this?
s
Exceptions from
async
always propagate to the outer scope in addition to being thrown from
await()
. In your example code, since you are using
suspend fun main
you do not need to create a separate
CoroutineScope
.
v
Exceptions from async always propagate to the outer scope in addition to being thrown from await()
But I'm catching that with runCathcing {}
s
You are catching the exception thrown from
await()
, but the exception will also be propagated to the parent scope. That’s just how
async
works.
v
How can I stop propagating it to parents, sorry I'm not good at coroutine concepts. Do I need to make the scope SuperVisor?
My intention is to not crash when this exception occur
s
In your example code, since you are using
suspend fun main
you do not need to create a separate
CoroutineScope
. If your actual application does need the additional scope, then yes, a supervisor scope could be a good solution 👍.
v
Copy code
suspend fun main() {
    val scope = CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO> + SupervisorJob())
    val validServer = embeddedServer(CIO, port = 8080){}.start(false)

    val addressReuseFailureServer = scope.async(start = CoroutineStart.LAZY) {
        embeddedServer(
            factory = CIO,
            environment = applicationEngineEnvironment {
                connector { port = 8080 }
            },
            configure = { reuseAddress = false }
        ).start(wait = false)
    }
    runCatching { addressReuseFailureServer.await() }.also { println(it) }
}
I made the scope SupervisorJob, but still the same
Copy code
fun main() {
    val exceptionHandler = CoroutineExceptionHandler { _, throwable ->
        println("Caught an exception: ${throwable.message}")
    }

    val validServer = embeddedServer(CIO, port = 8080){}.start(false)
    val addressReuseFailureServer =
        embeddedServer(
            factory = CIO,
            environment = applicationEngineEnvironment { parentCoroutineContext = exceptionHandler;connector { port = 8080 } },
            configure = { reuseAddress = false }
    )
    runCatching { addressReuseFailureServer.start(wait = false) }.also { println(it) }
}
I ended up with this,
Copy code
Failure(kotlinx.coroutines.JobCancellationException: LazyStandaloneCoroutine is cancelling; job=LazyStandaloneCoroutine{Cancelling}@71423665)
Caught an exception: Address already in use
The above code catch all exception but don't whether it's the right way of doing it.
a
I can successfully catch the exception if the scope is defined as
CoroutineScope(<http://Dispatchers.IO|Dispatchers.IO> + SupervisorJob())
.
114 Views