KRetryRunner

class KRetryRunner<T>(scope: CoroutineScope, val retries: Int = 3, val delay: Duration = 250.milliseconds, val backoffFactor: Double = 2.0, val maxDelay: Duration = 10.seconds, val onSuccess: (T) -> Unit? = null, val onError: (Throwable) -> Unit? = null)(source)

A utility that retries a suspending operation with configurable exponential back-off and jitter.

This is a Kotlin implementation of the useRetry pattern. It manages the lifecycle of asynchronous attempts, providing reactive state for loading status, current attempt count, successful values, and the last encountered error.

Example usage:

val runner = KRetryRunner<User>(
scope = viewModelScope,
retries = 3,
delay = 500.milliseconds,
backoffFactor = 2.0,
onSuccess = { user -> println("User fetched: ${user.name}") },
onError = { err -> println("Attempt failed: ${err.message}") }
)

// Trigger manually:
runner.launch { api.getUser(id) }

// Observe in UI:
val isLoading by runner.isLoading.collectAsState()
val error by runner.error.collectAsState()
val user by runner.value.collectAsState()

if (isLoading) CircularProgressIndicator()
error?.let { Text("Error: ${it.message}") }
user?.let { UserProfile(it) }

Parameters

scope

The CoroutineScope that owns the retry jobs.

retries

The maximum number of additional attempts after the first failure. Default: 3.

delay

The initial wait duration between the first and second attempt. Default: 250ms.

backoffFactor

The multiplier applied to the wait duration after each failure. Default: 2.0.

maxDelay

The maximum allowed delay between attempts. Default: 10s.

onSuccess

Optional callback invoked when an attempt succeeds.

onError

Optional callback invoked after each failed attempt.

Type Parameters

T

The type of the result produced by the asynchronous operation.

Constructors

Link copied to clipboard
constructor(scope: CoroutineScope, retries: Int = 3, delay: Duration = 250.milliseconds, backoffFactor: Double = 2.0, maxDelay: Duration = 10.seconds, onSuccess: (T) -> Unit? = null, onError: (Throwable) -> Unit? = null)

Properties

Link copied to clipboard
val attempt: StateFlow<Int>

The 1-based index of the current (or last completed) attempt.

Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
val error: StateFlow<Throwable?>

The last error seen, or null when successful.

Link copied to clipboard
val isLoading: StateFlow<Boolean>

Whether an operation is currently running.

Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
val onSuccess: (T) -> Unit?
Link copied to clipboard
Link copied to clipboard
val value: StateFlow<T?>

The last successful value, or null.

Functions

Link copied to clipboard
fun autoRun(block: suspend () -> T)

Keeps calling block immediately (useful for re-running when dependencies change). Cancels any previous auto-run job.

Link copied to clipboard
fun cancel()

Cancels any in-progress job without resetting state.

Link copied to clipboard
fun launch(block: suspend () -> T): Job

Launches block in scope with retries, returning the Job. Cancels any existing launch first.

Link copied to clipboard
fun reset()

Resets all state. Does not cancel a running job.

Link copied to clipboard
suspend fun run(block: suspend () -> T): T

Runs block with up to retries retries. Returns the successful value. Throws the last exception if all attempts are exhausted.

Link copied to clipboard
open override fun toString(): String