Runtime API (runtime)
The runtime scope object exposes read-only process state at hook entry. Use runtime.routing() for pool-wide health and in-flight counts aligned with Route.
For why this is separate from txn, see Host API overview.
Availability
| Piece | When present |
|---|---|
runtime in scope |
Every Rule Rhai hook run |
Meaningful runtime.routing() data |
Pool has health.enabled: true in config |
When health is disabled for a pool, views still work: configured() is true and counts reflect health-off semantics (eligible_count equals configured_count; per-backend applied is "up"). Unknown pool or backend names return empty views (configured: false).
When values are taken
When your script runs on the request hook or response hook, Conduit captures one routing and health snapshot at the start of that hook phase — before your first line of Rhai runs. The snapshot includes backend health (applied, observed, eligibility), EWMA, in-flight forward counts, and fail-open flags as they were at that moment.
It is not a view from process startup. Each runtime.routing().pool(...) or .backend(...) call in the same script reads that same snapshot — calls do not re-query live health.
| What to expect | Practical meaning |
|---|---|
| Captured at hook phase start | Request rules or response rules begin for this query on this worker; health and routing fields reflect state then. |
| Frozen while the script runs | Probes, conduitctl health drain/freeze, and config reload can change backends after the snapshot was taken. Your variables do not update until the next hook. |
| Snapshot build vs reads | Building the snapshot walks configured pools/backends once at hook entry (bounded by config size, outside Rhai max_operations). Each runtime.routing().pool() / .backend() call inside the script is an O(1) read and does count toward max_operations — see Sandbox limits — Host API and max_operations. |
| New snapshot each hook | Request hook, each response hook, and each retry response pass builds a fresh snapshot. Do not carry values from one hook to the next. |
| Close to the next Route pick | Route uses the same health sources when it selects the next backend on this query (Route reads again at selection time, so health can move in the short gap after your script). |
runtime.config_generation() (and txn.config_generation()) tell you which config generation the query is running under — useful after reload to gate new policy, not for measuring probe latency or sub-second health flaps.
Use runtime to branch policy (failover pool, retry on applied down). For live operational view, use metrics and conduitctl health — not Rhai reads on every query.
Query by name
runtime.routing() answers about pools and backends you name explicitly. Pass a pool name or backend id; Conduit returns health and routing for that target.
| You call | You pass | You get |
|---|---|---|
runtime.routing().pool(name) |
pool name (for example "primary") |
pool-wide counts and flags (eligible backends, fail-open, …) |
runtime.routing().backend(pool, id) |
pool + backend id | health and routing for that backend |
runtime.routing().backend_for_attempt(...) |
txn.selected_pool() and txn.selected_backend_name() |
same, for the forward attempt that just finished |
Where to get names:
- Config and rules — literal pool names in your script (
"primary","secondary"). - This query —
txn.selected_pool()/txn.selected_backend_name()on the response hook. lookup()tables — resolve qname or other keys to a pool name indata_sources:, then pass that string toruntime.routing().pool(...).- Several pools — name each pool in the script, or resolve names from a lookup table.
runtime
Top-level read-only methods on the runtime scope object.
Methods: runtime.config_generation() · runtime.routing()
runtime.config_generation()
Request + response hook · no args · returns i64
Snapshot generation captured when this hook run started.
Hooks
Request hook and response hook
Behavior
- Same generation as
txn.config_generation()on this query — both reflect the active config snapshot at hook entry. - Matches
conduit_config_generationfor that snapshot. - Use after reload to gate canary policy (for example only apply new logic when generation ≥ N).
runtime.routing()
Request + response hook · no args · returns RoutingRuntime
Routing and health snapshot for configured pools/backends.
Hooks
Request hook and response hook
Behavior
- Read-only — does not change routing, health, or transaction state.
- Built once when this hook phase begins from the health side-table, pool config, and outstanding-forward counts; every
runtime.routing()call in the same script shares it. - Per-call reads count toward sandbox
max_operations; snapshot build at hook entry does not.
RoutingRuntime
Returned by runtime.routing(). Pass a pool or backend name you already have — see Query by name.
Methods: pool(name) · backend(pool, id) · backend_for_attempt(pool, backend_id)
pool(name)
RoutingRuntime method · name: string · returns PoolRuntime
Summary for the whole pool — eligible backend count, fail-open, in-flight totals, and similar.
Hooks
Request hook and response hook
Behavior
namemust match apools[].namein config forconfigured() == true.- Unknown pool: empty view (
configured: false, counts0). - Does not select a pool for this query — use
txn.set_poolfor policy writes. - Returns
PoolRuntime— see Pool view for field methods (eligible_count,fail_open_active, …).
Example
Request-hook failover when not all backends are eligible (repository fixture routing-pool-failover.rhai):
let primary = runtime.routing().pool("primary");
if primary.configured() && primary.eligible_count() < primary.configured_count() {
txn.set_pool("secondary");
}
backend(pool, id)
RoutingRuntime method · pool, id: strings · returns BackendRuntime
Per-backend health/routing view at hook entry.
Hooks
Request hook and response hook
Behavior
pool— pool name;id— backendnamewhen set and unique in the pool, otherwiseip:port(same rules as metrics labels andconduitctl health).- Unknown pool/backend pair: empty view (
configured: false). - Use when you know the pool and backend identity from config or
lookup()— on the response hook preferbackend_for_attemptwithtxn.selected_*for the attempt that just completed. - Returns
BackendRuntime— see Backend view for field methods (applied,eligible, …).
backend_for_attempt(pool, backend_id)
RoutingRuntime method · two strings · returns BackendRuntime
View for a specific pool/backend pair — use with the current attempt context.
Hooks
Primarily response hook — also available on the request hook when txn.selected_pool() / txn.selected_backend_name() are already set.
Behavior
- Pass
txn.selected_pool()andtxn.selected_backend_name()for the forward attempt that just completed. - Empty
poolorbackend_idreturns an empty backend view (configured: false). - Same field semantics as
backend(pool, id)— convenience wrapper for response-hook retry and metrics branching.
Example
Response hook — retry when the attempt backend is applied down (repository fixture routing-backend-attempt.rhai):
let backend = runtime.routing().backend_for_attempt(
txn.selected_pool(),
txn.selected_backend_name()
);
if backend.configured() && backend.applied() == "down" {
txn.request_retry();
}
Pool view (PoolRuntime)
Returned by runtime.routing().pool("pool_name"). Methods below return pool-wide counts and flags such as eligible_count() and fail_open_active().
Methods: configured() · configured_count() · eligible_count() · fail_open_active() · min_latency_ewma_ms() · max_outstanding()
PoolRuntime.configured()
Returns bool — true when the pool exists in the active snapshot.
Behavior
falsefor unknown pool names — otherPoolRuntimefields on that view are empty or zero.truewhen the pool is defined in config, even whenhealth.enabledis false (counts then reflect health-off semantics).
PoolRuntime.configured_count()
Returns i64 — number of backends defined on the pool in config.
Behavior
- Counts all
pools[].backendsentries — not only currently eligible backends. - Compare with
eligible_count()to detect partial outage or drain.
PoolRuntime.eligible_count()
Returns i64 — backends with applied == up (Route eligibility semantics).
Behavior
- Matches the eligible set Route uses when health gating is active.
- When pool health is disabled, equals
configured_count()(all backends treated eligible). - When
fail_open_active()is true, Route may still send traffic to ineligible backends — scripts should check both when diagnosing behavior.
PoolRuntime.fail_open_active()
Returns bool — Route is ignoring health gating for this pool (all-down or below min_eligible floor).
Behavior
truewhen eligible backends fall belowpools[].health.min_eligible(or the pool has at most one backend and health gating would block all traffic).- Route may forward to backends with
applied == downwhile fail-open is active —eligible_count()alone does not predict the next hop.
PoolRuntime.min_latency_ewma_ms()
Returns () (unit) when unset, else float — minimum latency EWMA among pool backends with samples.
Behavior
- Aggregates probe latency EWMA across backends in the pool that have at least one sample.
- Returns Rhai unit
()when no backend in the pool has EWMA data yet. - Read-only hint for latency-aware branching — Route uses per-backend
weight_factor()for weighted selection, not this pool-level minimum alone.
PoolRuntime.max_outstanding()
Returns i64 — maximum in-flight forwards to any backend in the pool at hook entry.
Behavior
- Snapshot of concurrent upstream forwards per backend address at hook entry on this worker.
- Useful for overload or hot-spot detection before choosing a pool or retry target.
- Does not include queries still in earlier pipeline stages — only active forward attempts counted in the runtime view.
Backend view (BackendRuntime)
Returned by runtime.routing().backend(pool, id) or backend_for_attempt(...). Methods below read fields for that named pool/backend pair.
id is the configured backend name when set and unique in the pool, otherwise ip:port (same rules as metrics labels and conduitctl health).
Methods: configured() · applied() · observed() · eligible() · frozen() · weight_factor() · outstanding() · latency_ewma_ms() · last_transition_unix_ms()
BackendRuntime.configured()
Returns bool — true when the pool/backend pair exists in the active snapshot.
Behavior
falsewhen the pool is unknown, the backend id does not resolve, orbackend_for_attemptwas called with empty strings.truefor configured backends even when health is disabled (appliedis then"up"withobserved"unknown").
BackendRuntime.applied()
Return string — "up", "down", or "unknown".
applied is what Route uses.
Behavior
appliedis the health state Route uses for eligibility and weighted selection.- Operator drain (
set down) setsappliedtodownand freezes the scope, even when probes still reportobserved == up. Freeze alone holdsappliedwithout changing it. - Compare with
observed()when diagnosing probe vs operator override.
BackendRuntime.observed()
BackendRuntime.eligible()
Returns bool — true when applied == up.
Behavior
- Equivalent to
applied() == "up"— shorthand for Route eligibility checks. falsedoes not guarantee Route will skip this backend whenfail_open_active()is true on the pool.
BackendRuntime.frozen()
Behavior
truewhen an operatorconduitctl healthfreeze/drain applies to this pool/backend.- Often pairs with
observed() == "up"andapplied() == "down"— probes still succeed but Route treats the backend as down. - Scripts only read health — use
frozen()for policy branching. Freeze, drain, and resume are operator control-plane actions (conduitctl health), not Rhai calls.
BackendRuntime.outstanding()
Returns i64 — in-flight upstream forwards to this backend at hook entry.
Behavior
- Per-backend concurrent forward count on this worker at hook entry.
0when idle — use withmax_outstanding()on the pool for pool-wide load signals.
BackendRuntime.weight_factor()
Behavior
- Range 0.0–1.0 after EWMA-based latency damping —
1.0means full configured weight. - Lower values reduce selection probability for slower backends; updated by the probe scheduler, not by Rhai.
- Read-only — scripts cannot change weights through
runtime.
BackendRuntime.latency_ewma_ms()
Returns () when no probe sample yet, else float — latency EWMA in milliseconds.
Behavior
- EWMA of successful health-probe round-trip time for this backend (recent samples weigh more than older ones).
- Returns Rhai unit
()until the first probe sample exists. - Drives
weight_factor()over time — useful for logging or canary metrics, not for per-query weight overrides.
BackendRuntime.last_transition_unix_ms()
Returns () when unknown, else i64 — Unix ms of last observed/applied transition.
Behavior
- Milliseconds since Unix epoch when
observedorappliedlast changed for this backend. - Returns Rhai unit
()when no transition has been recorded yet. - Use for staleness checks (for example avoid retry storms immediately after a backend flaps).
Operator health vs script reads
| Mechanism | Path | Use |
|---|---|---|
conduitctl health / gRPC |
Control plane | Drain, freeze, resume — changes applied and scope |
runtime.routing() |
Hot path (Rhai) | Read applied, eligible, pool-wide counts for policy |
| Probe logs | backend health transition INFO |
Observe probe-driven changes in process logs |
Scripts only read health through runtime.routing() for policy branching. Freeze, drain, and resume are operator control-plane actions (conduitctl health), not Rhai calls.
Related
- Host API overview
- Transaction API (
txn) — policy writes - Pools and backends — config model
- gRPC and conduitctl — health — operator controls