poise-discovery 0.1.1

Versioned membership snapshots for Poise load balancing
Documentation

Poise

CI Supply chain MSRV 1.85 unsafe forbidden verification engineering book support license

Composable, runtime-independent load-balancing primitives for Rust.

Poise separates membership, eligibility, selection, dispatch, and feedback so that sophisticated routing remains explainable. Simple policies are small and direct. Affinity, topology, health, discovery, and readiness integrations build on the same contracts instead of hiding a second balancing system behind an adapter.

[!IMPORTANT] Poise is pre-1.0. Its behavioral contracts are heavily tested, and all six crates are published on crates.io. Use compatible 0.1 requirements and review release notes before upgrading because pre-1.0 API changes remain possible.

Engineering book

The Poise engineering book is the primary guide to policy choice, composition, failure semantics, operations, performance, security, and verification. It is generated from the Markdown in docs/, shares the Invariant Orrery's visual language, and retains mdBook's search, keyboard navigation, deep links, print view, and theme controls.

Start with Getting started for a first integration, Choosing a policy for a production decision, or Composition for the complete control loop.

Why Poise exists

Load balancing is larger than choosing an index. A production request passes through several independently fallible decisions:

flowchart LR
    D[Discovery] --> M[Versioned membership]
    M --> E[Eligibility]
    H[Health + circuits] --> E
    L[Load signals] --> E
    E --> P[Policy]
    P --> S[Selection]
    S --> R[Readiness-aware dispatch]
    R --> F[Outcome feedback]
    F --> H
    F --> L
    R --> O[Bounded observability]

Poise gives each boundary a concrete contract. Policies select; they do not dispatch. Discovery publishes immutable generations; it does not mutate a live candidate slice in place. Health and load are candidate signals; they do not silently replace selection semantics. Tower retains readiness after selection, and telemetry avoids endpoint-derived cardinality by default.

Workspace

Crate Responsibility Runtime dependency
poise-core Candidate contracts, selection policies, affinity, topology, and load trackers None
poise-discovery Atomic versioned snapshots, subscriptions, reconciliation inputs, and graceful draining None
poise-health Active probes, passive circuits, rolling outcomes, and group-relative outlier detection None
poise-tower Readiness-correct dispatch and optional snapshot-to-service reconciliation Tower
poise-tokio Optional probe timing and asynchronous discovery waits Tokio
poise-observe Fixed-cardinality counters and optional structured tracing Optional Tower / tracing

There is intentionally no umbrella crate. Applications depend only on the layers they use, and the deterministic policy core does not inherit an async runtime.

Policy surface

Family Included primitives Primary contract
Stateless selection Random, weighted random, power of two choices, least loaded Select only eligible, in-bounds candidates
Stateful rotation Round robin, smooth weighted round robin Stable cycles and explicit identity-keyed state
Affinity Rendezvous, weighted rendezvous, ring hash, Maglev Deterministic placement and bounded disruption under churn
Load-aware affinity Bounded-load weighted rendezvous Preserve affinity while enforcing prospective capacity
Priority Weighted priority tiers, overprovisioned failover, panic thresholds Select a health scope before endpoint weighting
Locality Health-adjusted locality weighting and spillover Preserve priority and topology metadata
Feedback In-flight accounting and peak EWMA RAII-safe load updates under completion and cancellation

See the focused contracts for weighted rendezvous, ring hash, Maglev, bounded-load affinity, priority routing, and locality routing.

Minimal policy example

use poise_core::{Backend, Policy, policy::RoundRobin};

let backends = [Backend::new("a"), Backend::new("b")];
let mut policy = RoundRobin::new();

let selected = policy.pick(&backends, &())?;
assert_eq!(backends[selected.index()].id(), &"a");
# Ok::<(), poise_core::PickError>(())

Selection returns an index plus policy-specific decision metadata. The caller retains ownership of the candidate collection and decides how dispatch, readiness, retries, and feedback are performed.

Composition model

Membership

poise-discovery publishes immutable, monotonically versioned snapshots. Readers keep valid handles to older snapshots while a newer generation becomes visible atomically. Removal can enter a draining state before physical retirement, and failed batches do not partially commit.

Eligibility

Candidates expose identity, status, and weight without forcing one concrete backend type. Health wrappers compose active classification, passive circuit state, outcome windows, and underlying service availability. Draining and operator opt-out are never revived by panic routing.

Selection

Policy implementations are deterministic when seeded, make empty and ineligible outcomes distinct, and do not own dispatch. Cached policies rebuild transactionally when relevant membership changes.

Dispatch

poise-tower polls readiness before policy selection and retains the selected service's readiness permit until the call. Invalid custom-policy indices, readiness failures, cancellation, and response errors remain explicit and endpoint-aware.

Feedback and observation

Load guards distinguish completion from cancellation. poise-observe records decision and attempt outcomes with fixed dimensions, saturating counters, and optional tracing spans without placing telemetry dependencies in the policy data plane.

For the full boundary model, read Architecture, the Tower dispatch contract, discovery reconciliation, Tokio integration, and observability.

Verification standard

Poise treats behavioral laws as public API.

  • 240 authored test entry points cover examples, edge conditions, distributions, concurrency, cancellation, and transactional failure.
  • 14 Proptest laws run 256 generated cases each by default and shrink failures into committed regression seeds.
  • Mutation testing requires every terminating viable poise-core mutation to be caught. The recorded full campaign examined 642 sites with zero viable survivors; watchdog-detected nontermination remains visible.
  • Six Loom models exhaustively explore scheduler interleavings around in-flight accounting and health state transitions.
  • MSRV verification runs the workspace and all features on Rust 1.85.
  • Doctests, strict Clippy, rustfmt, rustdoc, dependency policy, and package dry-runs are release gates.

Run the fast local gate:

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-features

Run the scheduler models separately:

scripts/model-check.sh

Mutation testing is intentionally explicit and resource-bounded. It is not part of the default local hook:

scripts/mutants-core.sh --jobs 1

Do not run the fuzz targets without reading the resource limits in Fuzzing and concurrency. The complete strategy is documented in Testing and verification and Mutation testing.

Invariant Orrery

The interactive capability showcase replays a structured verification record as a bounded kinetic system. It does not execute tests, fuzzers, or mutation workloads in a visitor's browser. The renderer caps particles and device pixel ratio, pauses offscreen, and provides semantic and reduced-motion fallbacks.

Its data contract distinguishes live, recorded, stale, failed, and unavailable evidence. GitHub Pages publishes failing runs as broken proofs while leaving the associated Actions workflow red. The same Pages artifact serves the engineering book, so the visualization and reference material always describe one revision.

Performance stance

The core is designed to be allocation-conscious and deterministic, but Poise does not publish unsupported performance claims. Criterion baselines across small and large backend sets are still a release-roadmap item. Until those baselines land, evaluate the exact candidate counts, churn rates, and policy families used by your deployment.

Compatibility and stability

  • Minimum supported Rust version: 1.85.
  • Edition: Rust 2024.
  • Unsafe Rust: forbidden by workspace lint.
  • SemVer: pre-1.0 compatibility rules apply; behavior documented as a contract is changed deliberately and called out in release notes.
  • Runtime neutrality: poise-core, poise-discovery, and poise-health do not require Tokio.

Contributing

Start with CONTRIBUTING.md. Changes to selection arithmetic, hashing, health boundaries, cached membership, topology, or concurrent load tracking need tests at the strongest applicable layer—not only a new example.

The repository uses Conventional Commits so release automation can distinguish fixes, features, and breaking changes. Install the repository-owned validation hook with:

scripts/install-hooks.sh

Releases

All workspace crates share one version. release-plz prepares dependency-aware release pull requests, performs SemVer API checks, updates the changelog, creates per-crate tags, and publishes in dependency order after the release PR is merged. A local scripts/bump-version.mjs command is available for an explicit maintainer override, and the pre-commit hook rejects partial version bumps.

The first crates.io publication completed on August 5, 2026. Subsequent releases use GitHub OIDC without a long-lived registry secret after trusted publishers are configured. See Release engineering.

Project status

The advanced policy, health, discovery, Tower, Tokio, observability, property, mutation, and Loom foundations are implemented. Remaining pre-1.0 priorities include criterion regression baselines, retry/hedge exclusion, adaptive concurrency, capacity-aware routing, and governance. See the roadmap.

Security

Please report vulnerabilities privately according to SECURITY.md. Do not open a public issue for a suspected vulnerability.

Support

If Poise is useful to your infrastructure, you can support its continued engineering and maintenance through TokenTip.

License

Poise is licensed under either the Apache License, Version 2.0 or the MIT license, at your option.