question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

retryResult signature makes it easy to use wrong context

See original GitHub issue

It seems that issue #4 was closed, but I have also inadvertently run into this situation today with similar code:

    withTimeout(1000) {
        retryResult {
            // This crashes because coroutineContext is obtained from the withTimeout scope
//            println("My retryStatus is ${coroutineContext.retryStatus}")

            // This is okay (naming conflict with coroutineContext)
            println("My retryStatus is ${kotlin.coroutines.coroutineContext.retryStatus}")

            // This is also okay
            coroutineScope {
                println("My retryStatus is ${coroutineContext.retryStatus}")
            }

            Ok(Unit)
        }
    }

I was able to workaround this issue fairly easily, but it is easy to shoot yourself in the foot. I understand it would be a breaking api change to update the type signature of ResultProducer. Is there any other reason why you wouldn’t want to provide the proper scope to the retryResult block?

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
michaelbullcommented, Dec 16, 2021

I’ve gone ahead and made a rather significant refactoring that would be part of a v2 in 2babe2a1f91308d642b66df4646aacb9eb0dcb78. The main benefit is that it removes the burden on the caller of interfacing with the coroutineContext. Instead, both the policies and the calling code are written in context of a RetryScope (analogous to a CoroutineScope or a SequenceScope from the stdlib), which gives readonly access to the attempts, previous delay, cumulative delay, etc.

This results in a lot less boilerplate in both the calling code and the policy implementations:

fun main() = runBlocking {
    retryPrint()
}

suspend fun retryPrint() = retry(constantDelay(10)) {
    if (attempt < 3) {
        throw Exception()
    } else {
        println("success after $attempt, took $cumulativeDelay milliseconds")
    }
}
fun limitAttempts(limit: Int): RetryPolicy<*> {
    require(limit > 0) { "limit must be positive: $limit" }

    return {
        if (attempt + 1 >= limit) {
            StopRetrying
        } else {
            ContinueRetrying
        }
    }
}
0reactions
vrendinacommented, Nov 15, 2021

I actually don’t think that will be a breaking change

The current type signature for retryResult (without the typealias) is:

suspend fun <V, E> retryResult(
    policy: RetryPolicy<E> = constantDelay(50) + limitAttempts(5),
    block: suspend () -> Result<V, E>
): Result<V, E> 

Updating the signature to include the CoroutineScope as the lambda receiver would break any clients that have explicitly defined the block type. Including those clients which are using method references for example ::someFunctionThatReturnsResult.

suspend fun <V, E> retryResult(
    policy: RetryPolicy<E> = constantDelay(50) + limitAttempts(5),
    block: suspend CoroutineScope.() -> Result<V, E>
): Result<V, E> 

Need to think a little more about the most appropriate solution.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Issues · michaelbull/kotlin-retry
Issues list. retryResult signature makes it easy to use wrong context. #18 opened on Nov 15, 2021 by vrendina.
Read more >
Retry Failing Tasks with Cats and Scala - Alexandru Nedelcu
And the raiseError function lifts an E error into the F[A] context (the equivalent of Java's and Scala's throw for exceptions).
Read more >
Retry a method based on result (instead of exception)
I have been using failsafe build in retry. You can retry based on predicates and exceptions. Your code would look like this:
Read more >
gotalk
Gotalk is a complete muli-peer real-time messaging library.
Read more >
Kubernetes contexts from agent not injected into pipeline of ...
This actually does not fix the issue. Without the KUBE_CONTEXT variable, the deployment will use the wrong context (the default one using the ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found