Hi, Ktor http client, with CIO as engine configure...
# arrow
l
Hi, Ktor http client, with CIO as engine configured with a request timeout (15 seconds by default), can throw a
TimeoutCancellationException
, which is a
CancellationException
. Hence, when using
Either.catch
to make a request, the exception is considered 'fatal', since
793a51edce
, and re-thrown. My question is, why is this considered fatal ? Thanks !
s
Hey @Leo Laudouard, cancellation exception should not be caught be default which is why this is the default behavior of Either.catch
You could use withTimeoutOrNull instead also
l
Ok, thanks! I'll dig on ktor side
s
We could consider adding
Either.catchFatal
for such use-cases 🤔 This has been on my mind for some time, since with this style it’s not easy to capture
TimeoutCancellationException
like you say. Or
Either.catchPrecise
where you can say
E : TimeoutCancellationException
so you get.
Copy code
val e: Either<TimeoutCancellationException, Unit> = Either.catchPrecise {
  withTimeout(...) {
    delay(...)
  }
}
l
For the use case I have, I would still need to catch other exceptions that could happen. For my knowledge, why not catching fatal exceptions ? To avoid losing them, I guess ?
Maybe add a parameter to allow overriding default fatal exceptions instead ?
s
Yes, a fatal exception should not be removed on the JVM since they put the JVM in an incorrect state. For example, after an OutOfMemory the JVM is unstable and recovering from it is advised against.
Same for
CancellationException
. The reason it’s thrown is so that async programs can be correctly closed using structured concurrency. If you accidentally swallow
CancellationException
then your program is prone to leaking async processes and recources
So not capturing them is a safer default
r
I think
catchFatal
makes sense for those programs that want to capture all exceptions such as profilers, logging frameworks etc. I think most other programs which is the great majority still benefit from the safe default behavior Simon described but there is a place for a explicit function IMO
l
First, thanks for your answers. Talking precisely about
withTimeout
and
TimeoutCancellationException
, I understand that an easy solution is to directly use
withTimeoutOrNull
. The problem comes from integration with other libraries. We cannot forbid usage of
withTimeout
. I do not consider
TimeoutCancellationException
to be a fatal exception, do you have an example ?
s
Right, you can indeed not forbid that. In this case I would just use
val either = try { Either.Right(f()) } catch(e: Throwable) { Either.Left(e) }
for now, rather than
Either.catch
.
You could also use
Result
which doesn’t catch fatal exceptions, and Arrow also offers computation blocks etc for them
@Leo Laudouard there are more details around this discussion here: