Hi! Let’s say I have this pseudo-code ```suspend f...
# arrow
j
Hi! Let’s say I have this pseudo-code
Copy code
suspend fun getMyData(): Either<ApiError, Response> =
    Either.catch {
        delay(1000)
        Response
    }.mapLeft {
        ApiError
    }

fun test() {
    val job = scope.launch {
        getMyData()
    }
    job.cancel()
}
Is
mapLeft
supposed to catch CancellationException? How can I make it propagate the cancellation rather than giving me a Either.Left?
s
Either.catch does rethrow cancellation exceptions
j
Do you have an example of how one should handle cancellation exceptions? From the little tests I did, I do get them caught inside the try/catch
I do get them caught inside the try/catch
Do you now mean an actual try/catch, or Either.catch?
j
I meant with Either.catch
c
Either.catch
will let fatal exceptions pass through, as it should
j
Alright, so I should have another try/catch around the call place where the cancellation is thrown? I'm encountering that issue with Ktor, when the client cancels a request.
s
From the little tests did, I do get them caught inside the try/catch
So, to confirm, you are now seeing the proper behavior of the cancellation propagating properly all the way through right? I am not sure what you want to catch there exactly. If the coroutine was cancelled, is it from the coroutineScope being cancelled? If so, it means the client is no longer interested in the response anymore. What do you want to try/catch it for, and what will you do with that information? I think some more context on what you're trying to do would be beneficial here 😊
1
j
I got more context from my coworker that is having the issue. > The app doesn’t crash, but it logs the cancellation as an error when it’s not really one. Then it was a false alarm since it is the intended behaviour. We just need to filter out manually the CancellationException out of the logs. Thanks for the help anyway! I got to learn some internal mechanism of
Either
c
We just need to filter out manually the CancellationException out of the logs.
No, that's not enough. Why are the logs able to know about it anyway? If they catch it
CancellationException
, you are creating zombies. You can hide the symptoms, but that doesn't solve the problem, it only makes it harder to debug. See https://betterprogramming.pub/the-silent-killer-thats-crashing-your-coroutines-9171d1e8f79b
s
Unless of course you just rethrow CancellationException, which solves this problem as it lets it propagate it through as it should. If you catch it for logging purposes and never throw it further, you are breaking structured concurrency indeed.
j
In addition of the
Either.catch
wrapping our ktor calls (they don’t check for any specific errors, they should propagate CancellationExceptions), our codebase has a
handleResponseExceptionWithRequest
with this
Copy code
val clientException = exception as? ClientRequestException ?: throw RestClientError.NetworkError(exception).also {
    logOtherExceptions(exception, request, corrId)
}
if (clientException.response.status.isSuccess()) {
    throw RestClientError.HttpError(clientException.message, clientException.response.status.value)
}
logClientRequestException(exception, request, corrId)
I’m not sure how a CancellationException go through this. but the ktor documentation doesn’t really specify anything more than what we do for cancelling a request https://ktor.io/docs/client-requests.html#cancel-request