Skip to content

withTimeoutOrNull returns null even when it did not timeout itself #67

Closed
@elizarov

Description

@elizarov

Copied from message by @gregschlom at public slack:

Hey guys. I have an issue with nested withTimeouts. Here’s some example code:

    val channel = Channel<Int>()

    // this blocks indefinitely if the channel is empty
    suspend fun nexValue(): Int {
        println("Waiting for next value ")
        return channel.receive()
    }

    // same as nextValue(), but returns null after the timeout expires
    suspend fun nextValueWithTimout(t: Long): Int? {
        return withTimeoutOrNull(t) { nexValue() }
    }

    suspend fun longOperation() {
        println("Starting long operation")
        while (true) {
            val v = nextValueWithTimout(1000)
            if (v == null) {
                println("timed out")
                // Nothing was received in our channel.
                // Do some other work while we wait for the value to arrive. Maybe we want to re-try sending
                // a message to our value producer for example
            }
            if (v == 42) return
        }
    }

    @Test
    fun main() = runBlocking {
        // This never returns. Instead we get stuck in an infinite loop in the while() above
        withTimeout(5000) {
            longOperation()
        }
    }

The problem here is that we have two nested withTimeout calls

The code is generally suspended inside nextValue(). When the outer timeout fires (the one in the main function), there’s no way for the code in nextValueWithTimout to know whether it was it’s own timeout that fired or some other timeout

Therefore it returns null either way

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions