v0.7.0 — Observability
Pre-releasethrottle-net v0.7.0 — Observability
See what the limiters are doing in production. v0.7.0 instruments the whole stack — metrics and tracing events around every acquire and every state transition — and it is feature-gated and genuinely zero-cost when off. No breaking changes.
What is throttle-net?
A general-purpose outbound throttling and resilience library. Where rate-net protects your service from being overwhelmed (inbound), throttle-net protects your service from overwhelming the downstreams it calls — and from being banned by them. It paces outbound work, composes limits across dimensions and scopes, retries, fails fast, queues fairly, adapts its concurrency, syncs to provider headers, and — as of this release — reports what it is doing.
What's new in 0.7.0
Metrics (feature metrics)
Emitted through the metrics facade, so they land in whatever recorder your application installs (Prometheus, StatsD, OTLP, …):
| Metric | Type | Emitted when |
|---|---|---|
throttle_acquired_total |
counter (label limiter) |
a waiting acquire is granted |
throttle_wait_duration |
histogram, seconds (label limiter) |
a waiting acquire completes |
throttle_queue_depth |
gauge | the queue's waiter count changes |
throttle_circuit_state |
gauge (0/1/2 = closed/half-open/open) | a circuit-breaker transition |
throttle_rate_current |
gauge | an adaptive limit changes |
Tracing events (feature tracing)
Emitted under the throttle_net target: an acquire event carrying limiter, cost, granted, and wait_secs, plus structured events for every documented state transition — circuit-breaker transitions, adaptive limit changes, queue overflow, and queue deadline exhaustion.
Zero-cost when disabled
The instrumentation routes through a small internal layer of #[inline] hooks. With the features off, each hook compiles to an empty function that the optimizer removes, and — critically — its inputs are never evaluated, so the hot path pays nothing. The wait timer is literally zero-sized in that build, which a test asserts. Each hook is also gated to the feature of the limiter that calls it, so the crate has no dead code in any feature combination.
// Wire up any recorder/subscriber in your app; the limiters emit automatically.
// e.g. with the `metrics` feature and a Prometheus recorder installed:
let throttle = throttle_net::Throttle::per_second(100);
// throttle.acquire().await? now increments `throttle_acquired_total`
// and records `throttle_wait_duration`.Breaking changes
None. Observability is additive and behind the metrics / tracing features.
Verification
Run on Windows x86_64, Rust stable 1.93.1; the same commands run in the CI matrix on Linux, macOS, and Windows across stable and MSRV 1.85:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo clippy --all-targets --no-default-features -- -D warnings
cargo test --all-features
cargo test --no-default-features
cargo test # default: metrics/tracing off (zero-cost path)
cargo doc --no-deps && RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features
cargo deny check
cargo auditAll green. Counts at this tag (--all-features): 129 unit tests, 7 property tests, 3 circuit-breaker integration tests, 2 retry integration tests, 1 observability integration test, 67 doctests. The exit criteria are covered directly: a test asserts the wait timer is zero-sized with the features off (zero-cost), and the observability integration test installs a local recorder and asserts the throttle_circuit_state gauge fires on a breaker trip (events fire on transitions). Every transition site routes through a hook, and each is exercised by an existing state-transition test.
This release also confirmed the feature matrix is clean: the lib builds under std-only, circuit-breaker-only, adaptive-only, metrics+tracing-only, and provider-llm-only, with no dead code in any combination.
What's next
- v0.8.0 — Runtime flexibility + feature freeze. async-std and smol support behind feature flags, a
no_std-capable algorithm core, the example set filled out, and the feature surface declared frozen for the run to 1.0.
Installation
[dependencies]
throttle-net = "0.7"
# Observability is behind feature flags:
throttle-net = { version = "0.7", features = ["metrics", "tracing"] }MSRV: Rust 1.85.
Documentation
Changelog: CHANGELOG.md.
Full Changelog: v0.6.0...v0.7.0