Skip to content

add-retry-error - #4

Merged
azeemshaik025 merged 3 commits into
mainfrom
retry-error
Aug 9, 2026
Merged

add-retry-error#4
azeemshaik025 merged 3 commits into
mainfrom
retry-error

Conversation

@azeemshaik025

Copy link
Copy Markdown
Owner

No description provided.

A retry that gave up handed back the last error and nothing else. That
error can't tell you whether you burned three retries in 700ms, spent a
30s budget, or had `.when` reject the first error so nothing was ever
retried. Three different incidents, identical output.

Both drivers now fail with `RetryError<E>`, carrying the last error plus
`attempts()`, `elapsed()`, and a `stop_reason()`. Building it lives in one
shared `give_up` so the two drivers can't drift on the arithmetic.

`impl Error` is bounded on `E: Debug + Display`, not `E: Error + 'static`.
The two overlap, so it's one or the other (E0119), and Debug+Display
covers strictly more: `String`, `Box<dyn Error>`, and `anyhow::Error` all
satisfy it and none implement `Error`. Retrying an `anyhow::Result` is
about as common as application code gets, and the alternative makes it
un-`?`-able. The cost is no `source()`; the inner error's text still rides
in `Display`.

The async driver now starts its clock on the first poll rather than at
`.into_future()`, matching blocking. That gap was invisible until
`elapsed()` made it public, and it also stops a future parked in a
`FuturesUnordered` from billing the wait to the operation.

Escape hatch is one call: `.map_err(RetryError::into_error)`.

Clock reads stay O(1): two with no budget regardless of retry count, and
the `MaxElapsed` path reuses the read its own budget check just did. The
old exact-count test is now a slope assertion over 3 and 30 retries, and
the blocking mock gained the same counter so both drivers pin it.

Mutation-checked: reporting retries instead of attempts, an ungated
give-up event, dropping the MaxElapsed clock reuse, a wrong stop reason in
either driver, elapsed measured from zero, and sampling start at
conversion time all fail the suite.

ADR005 records the always-wrap call, the Error bound with its coverage
table, bounded Display, no PartialEq, and the clock-start move.
The old branch was based on the pre-review jitter tip, so it was missing
the six commits main gained during review, and its ADR005 collided head-on
with the ADR005 that shipped in 0.3.0.

Rebuilt off main, carrying only the RetryError work. Its ADR is now ADR006;
main's ADR005 (testability) keeps the number it shipped under. Four
conflicts, all real: both sides had added an ADR005, both had added tests
at the same point in the blocking module, and both had written a new crate
docs section and a new index row.

The blocking tests main added during review are kept and retyped for the
new `call()` signature, so the driver parity that release established
survives the rebuild: both drivers now carry the same four tests.

CHANGELOG entry rewritten in the style 0.3.0 settled on -- what changed and
what to do about it, with the reasoning in the ADR.

The old branch is preserved as archive/retry-error-pre-rebuild.
Outside-in pass on 0.4.0, written as a user following the CHANGELOG.

Everything the release claims holds. `?` into anyhow::Result works for
io::Error, String, Box<dyn Error> and anyhow::Error itself -- the last
three do not implement std::error::Error, which is the entire reason
ADR006 bounds the impl on Debug + Display. downcast_ref recovers
attempts and stop_reason, which is what ADR006 offers in place of
source(). Both drivers verified: when() gives not_retryable with
attempts 1, max_elapsed gives an elapsed strictly under the budget.

Two gaps found. The upgrade guide covered `match e` but not assert_eq!
on the whole Result, which is what every existing test does and which
fails with a bare E0369 that does not say what to do. And keywords still
lacked `jitter` -- swapped for `async`, the most generic of the five and
already implied by `tokio`.
@azeemshaik025
azeemshaik025 merged commit 9ecee25 into main Aug 9, 2026
14 checks passed
@azeemshaik025
azeemshaik025 deleted the retry-error branch August 9, 2026 12:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant