All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.valaphee.foundry.retry.Retry.kt Maven / Gradle / Ivy

/*
 * Copyright (c) 2021, Valaphee.
 * All rights reserved.
 */

package com.valaphee.foundry.retry

import com.valaphee.foundry.retry.context.RetryStatus
import com.valaphee.foundry.retry.context.retryStatus
import com.valaphee.foundry.retry.policy.RetryPolicy
import com.valaphee.foundry.retry.policy.constantDelay
import com.valaphee.foundry.retry.policy.limitAttempts
import com.valaphee.foundry.retry.policy.plus
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

@ExperimentalContracts
suspend fun  retry(policy: RetryPolicy = defaultPolicy, block: Producer): T {
    contract {
        callsInPlace(policy, InvocationKind.UNKNOWN)
        callsInPlace(block, InvocationKind.AT_LEAST_ONCE)
    }

    return withContext(RetryStatus()) {
        lateinit var mostRecentFailure: Throwable
        while (true) {
            try {
                return@withContext block()
            } catch (ex: CancellationException) {
                throw ex
            } catch (t: Throwable) {
                val status = coroutineContext.retryStatus
                status.incrementAttempts()
                when (val instruction = RetryFailure(t).policy()) {
                    StopRetrying -> {
                        mostRecentFailure = t
                        break
                    }
                    ContinueRetrying -> {
                        status.previousDelay = 0
                        continue
                    }
                    else -> {
                        val delay = instruction.delay
                        delay(delay)
                        status.previousDelay = delay
                        status.incrementCumulativeDelay(delay)
                    }
                }
            }
        }
        throw mostRecentFailure
    }
}

@ExperimentalContracts
suspend fun  Producer.retry(policy: RetryPolicy = defaultPolicy): T {
    contract {
        callsInPlace(policy, InvocationKind.UNKNOWN)
        callsInPlace(this@retry, InvocationKind.AT_LEAST_ONCE)
    }

    return retry(policy, this)
}

private val defaultPolicy: RetryPolicy = constantDelay(50) + limitAttempts(5)
private typealias Producer = suspend () -> T




© 2015 - 2024 Weber Informatics LLC | Privacy Policy