Should cleanup inside withTimeout run in NonCancellable, or is a finally block enough?
0 reputation · 17 May 2025, 06:54 UTC
I'm designing a Kotlin coroutine that performs a network fetch wrapped in withTimeout, and on timeout I need to release a resource (close a connection and write a short audit log entry). I understand that withTimeout throws TimeoutCancellationException, which is a subtype of CancellationException, and that once the coroutine is cancelled, further suspending calls in a normal finally block will immediately re-throw.
The documented behavior I've seen is that cleanup requiring suspension should be wrapped in withContext(NonCancellable), while purely synchronous cleanup can stay in a plain finally. What I'm unsure about is the boundary: my audit logging goes through a suspending API, and I also catch exceptions around the block to distinguish timeout from other failures.
Specifically:
- If I catch
TimeoutCancellationExceptionoutside thewithTimeoutcall, is the surrounding coroutine still considered cancelled at that point, or only the timed block? - Is wrapping the suspending cleanup in
withContext(NonCancellable)the correct and sufficient pattern here, or are there pitfalls when the parent scope itself is also being cancelled? - Should I rethrow
CancellationExceptionafter cleanup to preserve structured concurrency, even when I handled the timeout case deliberately?
Assume kotlinx-coroutines 1.7+ on the JVM. I'd like to confirm the intended pattern before committing to it.