```private suspend fun connectAndStartListening() ...
# coroutines
u
Copy code
private suspend fun connectAndStartListening() = coroutineScope {
    val webSocketSession = ktorClient.webSocketSession("<ws://10.0.2.2:8765>")

    launch {
        for (frame in webSocketSession.incoming) {
            Log.d("Default", "frame=$frame")
        }
    }
    ... stuff
}
I want to add graceful closing when this coroutine gets cancelled. How do I listen for cancellation of this function?
Copy code
launch {
   awaitCancellation()
   webSocketSession.close()
}
like this?
z
Copy code
private suspend fun connectAndStartListening() {
    val webSocketSession = ktorClient.webSocketSession("<ws://10.0.2.2:8765>")

    // Assuming the session implements AutoCloseable
    webSocketSession.use {
        coroutineScope {
            launch {
                for (frame in webSocketSession.incoming) {
                    Log.d("Default", "frame=$frame")
                }
            }
            ... stuff
        }
    }
}
u
Copy code
public interface WebSocketSession : CoroutineScope
so.. I dont think so? also now im noticing,
close
is a suspend function
Copy code
public suspend fun WebSocketSession.close(reason: CloseReason = CloseReason(CloseReason.Codes.NORMAL, ""))
z
then replace
use
with try/finally
u
but, which part exactly will throw? I was expecting some sort of callback api
z
Presumably whatever suspends? I’m guessing incoming? I don’t know this api so maybe I’m totally wrong
u
btw if I run a suspend function in finally; doesnt that break the structured concurrency?
z
Nope that’s fine
The coroutine will be in a “canceling” state while finally blocks run and join calls won’t resume until all finally blocks are done.
u
alrighty, thanks !
Copy code
private suspend fun listenAndSend(webSocketSession: DefaultClientWebSocketSession) = coroutineScope {
    val channel = Channel<ByteArray>(capacity = Channel.BUFFERED)
    launch {
        while (isActive) {
            val bytes = queryMicrophone()
            channel.send(bytes)
        }
        channel.close()
    }

    for (bytes in channel) { <-------
        webSocketSession.send(bytes)
    }
}
If I may follow up would you wrap this loop in launch or not?
z
No
👍 1
u
@Zach Klippenstein (he/him) [MOD] sorry to resurect this but I don't think I understand what you meant. Running a suspend function in finally seems to do nothing once the coroutine was cancelled? it hits first suspension point, which throws cancellation exception and rest is a no-op then. So basically it doesnt do anything (?)
z
Yes, anything that would normally check for cancellation and throw will continue to do so in a finally. That is extremely not “doesn’t do anything”. There are an infinite number of things you can do that don’t check coroutine cancellation, and if you do need to call something that checks you can wrap in a NonCancellable context. Closing resources is a very common use case.
u
yes but if it's a normal high level suspend function, it does nothing - so an odd choice on the ktor part