Hi, everyone, I want to implement a timeout except...
# coroutines
l
Hi, everyone, I want to implement a timeout exception retry mechanism, I wrote the blow code. But the timeout doesn’t work well, it only throw the
CommConnectionException
but never throw the
TimeoutCancellationException
. So why the timeout doesn’t work well? How to fix it?
Copy code
private suspend fun realConnectBluetoothDevice(): Boolean {
        if (bluetoothCommConnection.isConnected) {
            return true
        }

        repeat(5) {
            L.e("the $it times to connect bluetooth device")
            try {
                return@realConnectBluetoothDevice blockConnect(5000L)
            } catch (e: CommConnectionException) {
                if (it == 4) {
                    throw e
                }
            } catch (e: TimeoutCancellationException) {
                if (it == 4) {
                    throw e
                }
            }
        }

        throw CommConnectionException("connect bluetooth device failed")
    }

    private suspend fun blockConnect(timeout: Long) = try {
        withTimeout(timeout) {
            withContext(Dispatchers.IO) {
                try {
                    bluetoothCommConnection.open()
                    // bluetoothCommConnection.isConnected is a Boolean value
                    bluetoothCommConnection.isConnected
                } catch (e: CommConnectionException) {
                    bluetoothCommConnection.closeImmediately()
                    throw e
                }
            }
        }
    } catch (e: TimeoutCancellationException) {
        bluetoothCommConnection.closeImmediately()
        throw e
    }
r
Cancellation is cooperative - the withTimeout will cancel the block but if nothing in the block checks for the cancellation then it'll keep running as if it never happened. Most standard coroutine APIs (such as delay) will do this for you but blocking APIs have no idea that they're inside coroutines so will not
If you know your
bluetoothCommConnection
supports Java interruptions you may get expected behaviour by replacing
withContext
with
runInterruptible
🙌 1
l
😂Sorry, I wrote wrong code, it just like this now
And,
bluetoothCommConnection.closeImmediately()
will interrupt the
bluetoothCommConnection.open()
and return immediately
r
If runInterruptible doesn't work but you have an interrupt method you can try calling it like:
Copy code
suspendCancellableCoroutine {
                    it.invokeOnCancellation{
    interruptMethod()
                    }
                    
it.resume(blockingMethod()) { 
}
                }
🫡 1