Failover
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-badIf every provider is either skipped (circuit open) or fails, execute throws FailoverExhaustedException describing why each provider was unavailable.