feat(net): Retry resilience layer (Slice 1, PR 3)#82
Conversation
Explicit-only Retryable eligibility (tightens ADR-0031 §2), transient-error + 5xx trigger set with no-retry-429, capped-exponential full-jitter backoff via an internal seeded SplitMix64 (no rand dep, no Jitter generic), body- transparent, attempts+backoff budget. MockTimer + inline-double testing. Lands as ADR-0034 amendment #8. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds RetryLayer<T> + Retry<S, T>: re-issues an eligible request on a transient error (Timeout/Connection) or a 5xx response, with capped-exponential full-jitter backoff, via the crate's SplitMix64 PRNG (Task 2). Body-transparent; drops the superseded response (releasing any Guarded permit) before backing off.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughThis PR adds a ChangesRetry Layer Implementation
Estimated code review effort: 3 (Moderate) | ~30 minutes Possibly related issues
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/superpowers/plans/2026-07-04-net-http-retry-layer.md`:
- Around line 309-320: The full-jitter helper in `duration_in` has an off-by-one
edge when the ceiling reaches `u64::MAX`, because the current `checked_add(1)`
path drops the inclusive upper bound. Update `duration_in(&self, ceil:
Duration)` to use a wider `u128` modulus (or equivalent wider arithmetic) when
sampling so the result remains uniformly inclusive over `[0, ceil]` even at the
maximum ceiling, while still preserving the existing zero-ceil fast path and
`Duration::from_nanos` conversion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 7453b13e-6261-49d3-b231-0498c1683f96
📒 Files selected for processing (6)
CHANGELOG.mdcrates/adapter/net/http/api/src/lib.rscrates/adapter/net/http/api/src/retry.rsdocs/adr/0034-http-construction-surface-auth-guarded-boot-coverage.mddocs/superpowers/plans/2026-07-04-net-http-retry-layer.mddocs/superpowers/specs/2026-07-04-net-http-retry-layer-design.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CodeRabbit (PR #82): duration_in's saturating_add(1) modulus dropped the inclusive top value at ceil_nanos == u64::MAX (a ~584-year cap). Sample now uses checked_add(1).map_or_else(full-u64-draw, % (n+1)), so [0, ceil] is inclusive for every representable ceiling and the u64::MAX edge falls back to the bare u64 draw (already uniform over [0, u64::MAX]). Adds a regression test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes #81
Slice 1 PR 3 of the net-http resilience layers (spec: docs/superpowers/specs/2026-07-04-net-http-retry-layer-design.md; ADR-0031 §2). Builds on RateLimit (#76) and Timeout (#78).
Retry<S, T>+RetryLayer<T>(net-api::Layer) — order-safe retry: re-issues an explicitly-eligible request (aRetryablemarker; absent → never retried, so a forgotten stamp never duplicates aPOST) on a transient failure (HttpError::{Timeout, Connection}) or a 5xx response, with capped-exponential full-jitter backoff up tomax_attempts.Auth/Throttled(ADR-0031 §2/§5); returns the last outcome verbatim on exhaustion.Guardedpermit;Auth/RateLimitre-run per attempt (they sit insideRetry).Runtime-neutral: generic over
net-api::Timer, jitter via an internal seededSplitMix64— norand, no new dependency, no injectedJittergeneric. MockTimer-driven tests with inline service doubles (+ the productionGuardedfor the permit-release test).Next: Slice 1 PR 4 — the
CircuitBreakerlayer.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests