You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
backon is already the workspace retry engine and app/src/retry.rs (the Charon app/retry port) is built on it — but the workspace has drifted into at least 5 distinct backoff parameter sets and 4 drive mechanisms:
core::expbackofffast() (100ms/5s) and default() (1s/120s) — used by scheduler/sse/bootnode, sometimes driven manually via .next() + expect.
p2p/src/relay/dial.rs#L104-L126 — a hand-written duplicate of expbackoff::default() (its doc even cites the same Charon config), reimplemented because p2p needs a pollable Duration rather than an async wrapper.
quic_upgrade.rs — a third scheme in units of minutes (1→512, doubling).
eth1wrap — Alloy's RetryBackoffLayer::new(10, 1000, 100), a fourth policy in a foreign library's units.
Fixed-delay loops in dkg/sync (250ms), cli test/peers (for attempt in 0..5, 5s intervals). Same family: dkg busy-polls node signatures on a 100ms ticker, re-locking and cloning the accumulated slot vector every tick (nodesigs.rs#L144-L164), and exchanger.rs#L561 polls with a bare 100ms sleep — both want a Notify/watch signal instead of a poll.
Meanwhile, components that should retry just give up and wait for the next tick: scheduler resolve_duties errors are logged "(retrying next slot)" — a beacon-node blip loses a slot's duty resolution; bcast/recast retries next epoch; the wire-layer store/broadcast sinks log and swallow errors (wire.rs#L739-L746 and siblings) — precisely the points Charon wraps in async-retry.
Proposed change
One retry module (the existing app::retry + core::expbackoff, merged or clearly layered) exposing the named policies (fast, default, plus a pollable-Duration helper for poll-based behaviours so relay/dial.rs can delete its copy).
Replace the manual .next()/hand-rolled loops with backon's Retryable or the shared pollable helper; express eth1wrap's policy in the same config vocabulary.
Inject retries at the give-up sites above (scheduler duty resolution, recast, wire sinks), with per-duty deadlines from the existing DeadlineCalculator plumbing. feat(app): wrap duty callbacks with the retry executor #534 covers the five Charon duty-callback wrap points; this issue covers the config unification and the remaining sites.
Summary
backonis already the workspace retry engine andapp/src/retry.rs(the Charonapp/retryport) is built on it — but the workspace has drifted into at least 5 distinct backoff parameter sets and 4 drive mechanisms:retry.rsdefaults (250ms/12s/1.6) — zero call sites (feat(app): wrap duty callbacks with the retry executor #534 tracks wiring it into the duty callbacks).core::expbackofffast()(100ms/5s) anddefault()(1s/120s) — used by scheduler/sse/bootnode, sometimes driven manually via.next()+expect.p2p/src/relay/dial.rs#L104-L126— a hand-written duplicate ofexpbackoff::default()(its doc even cites the same Charon config), reimplemented because p2p needs a pollableDurationrather than an async wrapper.quic_upgrade.rs— a third scheme in units of minutes (1→512, doubling).eth1wrap— Alloy'sRetryBackoffLayer::new(10, 1000, 100), a fourth policy in a foreign library's units.dkg/sync(250ms),cli test/peers(for attempt in 0..5, 5s intervals). Same family:dkgbusy-polls node signatures on a 100ms ticker, re-locking and cloning the accumulated slot vector every tick (nodesigs.rs#L144-L164), andexchanger.rs#L561polls with a bare 100mssleep— both want aNotify/watchsignal instead of a poll.Meanwhile, components that should retry just give up and wait for the next tick:
scheduler resolve_dutieserrors are logged "(retrying next slot)" — a beacon-node blip loses a slot's duty resolution;bcast/recastretries next epoch; the wire-layer store/broadcast sinks log and swallow errors (wire.rs#L739-L746and siblings) — precisely the points Charon wraps in async-retry.Proposed change
app::retry+core::expbackoff, merged or clearly layered) exposing the named policies (fast,default, plus a pollable-Durationhelper for poll-based behaviours sorelay/dial.rscan delete its copy)..next()/hand-rolled loops withbackon'sRetryableor the shared pollable helper; expresseth1wrap's policy in the same config vocabulary.DeadlineCalculatorplumbing. feat(app): wrap duty callbacks with the retry executor #534 covers the five Charon duty-callback wrap points; this issue covers the config unification and the remaining sites.