🙇‍♂️

Kotlin CoroutineのTimeoutCancellationExceptionがcatchできない

2022/06/10に公開

TimeoutCancellationExceptionがcatchできない

withTimeout()を使ってcoroutineのタイムアウト処理を書いていた時、タイムアウトした時にwithTimeout()がthrowするTimeoutCancellationExceptionがcatchできずに少しハマりました。

catchできないコード例

try {
    // withTimeout()がTimeoutCancellationExceptionをthrowしたとしても
    withTimeout(1000) {
        doWork()
    }
} catch (e: CancellationException) {
    // 1. こっちでcatchされる
    println("cancelled")
} catch (e: TimeoutCancellationException) {
    // 2. こっちでcatchできない
    println("timeout")
}

上のコード例だと、tryの中でwithTimeout()がTimeoutCancellationExceptionをthrowしたとしても
2.ではcatchできずに1.でcatchされます。

なぜ?

理由は明確で、TimeoutCancellationExceptionはCancellationExceptionを継承しているからです(ドキュメント読め、という話ですが...)。

名前からしても推測できることですよね。
ドキュメントきちんと読まずに使っていたバチが当たりました...

どうすればよいか

以下のように、先にTimeoutCancellationExceptionをcatchするようにします。

try {
    // withTimeout()がTimeoutCancellationExceptionをthrowすると
    withTimeout(1000) {
        doWork()
    }
} catch (e: TimeoutCancellationException) {
    // ちゃんとcatchできます
    println("timeout")
} catch (e: CancellationException) {
    // こっちは呼ばれません
    println("cancelled")
}

ドキュメント読みます...

Discussion