hello, everyone, I want to implement a timeout ret...
# coroutines
l
hello, everyone, I want to implement a timeout retry mechanism, i wrote below code, but it would not print
Timeout
after each 1 seconds, it just print
Timeout
after each 3 seconds. So how to fix it?
Copy code
fun main() = runBlocking {
    repeat(5) {
        try {
            withTimeout(1000) {
                withContext(Dispatchers.IO) {
                    ensureActive()
                    println("${Date(System.currentTimeMillis())}: Coroutine is running $it")
                    suspendCancellableCoroutine<Boolean> { continuation ->
                        continuation.resume(blockCall())

                        continuation.invokeOnCancellation {
                            println("${Date(System.currentTimeMillis())}: Coroutine is cancelled")
                        }
                    }
                }
            }
        } catch (e: TimeoutCancellationException) {
            println("${Date(System.currentTimeMillis())}: Timeout")
        }
    }
}

/**
 * it is a block call that takes 3 seconds to complete
 */
private fun blockCall() = try {
    Thread.sleep(3000)
    true
} catch (e: Exception) {
    false
}
e
cancellation is cooperative, and
blockCall()
isn't
suspend
so it can't be cancelled
there is a bridge to Java thread interruption which you should try instead
Copy code
fun main() = runBlocking {
    repeat(5) {
        withTimeoutOrNull(1000) {
            println("starting")
            runInterruptible(Dispatchers.IO) {
                blockCall()
            }
        } ?: println("timeout")
    }
}
🙌 1
🫡 1
l
I works well for
Thread.sleep(3000)
. But if
Thread.sleep(3000)
change to BluetoothSocket.connect() , it will timeout until the
blockCall()
complete.
Copy code
lifecycleScope.launch {
    repeat(5) {
        try {
            withTimeout(1000) {
                println("${Date(System.currentTimeMillis())}: starting")
                runInterruptible(Dispatchers.IO) {
                    blockCall()
                }
            }
        } catch (e: TimeoutCancellationException) {
            // call the BluetoothSocket.close() will immediately interrupt BluetoothSocket.connect()
            // BluetoothSocket.close()
            println("${Date(System.currentTimeMillis())}: timeout")
        }
    }
}

private fun blockCall() = try {
    // Thread.sleep(3000)
    // it is a block call that maybe takes 10 seconds to complete
    // BluetoothSocket.connect()
    true
} catch (e: Exception) {
    println("${Date(System.currentTimeMillis())}: exception")
    false
}
e
if it doesn't respect thread interruption (probably it calls native code so it can't be interrupted) then you can't interrupt it
d
From the linked doc:
close()
can be used to abort this call from another thread.
Would calling
close()
in
invokeOnCancellation
work as you expect?