Failover

class Failover<T>(source)

Failover pattern: try a prioritized list of named providers, falling through to the next one when the current provider's circuit is open or it fails outright.

Useful when the same logical operation can be satisfied by more than one concrete implementation and you want to prefer one over the others — e.g. a realtime transport that prefers WebSocket but degrades to MQTT, then to HTTP long-polling, if the preferred option is currently unhealthy.

Each provider gets its own CircuitBreaker. A provider that keeps failing has its breaker trip open, so subsequent calls skip it immediately instead of paying its timeout/latency again — and the breaker's own half-open/reset-timeout behavior periodically re-probes it, so Failover self-heals back to the preferred provider once it recovers, with no extra bookkeeping needed from the caller.

Basic usage:

val transport = failover<Connection> {
provider("websocket") { connectWebSocket() }
provider("mqtt") { connectMqtt() }
provider("http-polling") { connectHttpPolling() }
}

val connection = transport.execute()

Per-provider circuit breaker tuning:

val transport = failover<Connection> {
provider("websocket", circuitBreakerConfig = { failureThreshold = 3 }) {
connectWebSocket()
}
provider("mqtt") { connectMqtt() }
}

Inspecting provider health:

transport.providerNames() // ["websocket", "mqtt", "http-polling"]
transport.stateOf("websocket") // CircuitBreakerState.Open, once it's known-bad

If every provider is either skipped (circuit open) or fails, execute throws FailoverExhaustedException describing why each provider was unavailable.

Functions

Link copied to clipboard
suspend fun execute(): T

Tries each provider in priority order, returning the result of the first one that succeeds.

Link copied to clipboard

Names of all configured providers, in priority order.

Link copied to clipboard
fun startHealthProbing(scope: CoroutineScope, interval: Duration = 30.seconds): Job

Starts actively probing every currently-open provider on a fixed interval, instead of waiting for real traffic to pass through execute and incidentally test them.

Link copied to clipboard
suspend fun stateOf(name: String): CircuitBreakerState?

Current circuit-breaker state of the named provider, or null if no such provider exists.

Link copied to clipboard

Per-provider invocation statistics, in priority order.