Skip to content

Add on_give_up callback#127

Merged
kamui merged 2 commits into
4.xfrom
feat/on-give-up-callback
May 27, 2026
Merged

Add on_give_up callback#127
kamui merged 2 commits into
4.xfrom
feat/on-give-up-callback

Conversation

@kamui
Copy link
Copy Markdown
Owner

@kamui kamui commented May 26, 2026

Summary

Introduces an on_give_up callback that runs once when Retriable stops retrying after a rescued retriable exception. The callback receives (exception, try, elapsed_time, next_interval, reason), where reason is :tries_exhausted or :max_elapsed_time.

Targets the 4.x branch and inherits its Ruby 3.0+ minimum plus 4.0 timeout-option removal.

This single callback covers both requested features:

Design decisions

  • Name: on_give_up mirrors the existing on_retry shape (on_<event>).
  • Signature: matches on_retry's 4-arity then adds reason as the 5th argument. Procs ignore extra args, so existing handler patterns translate directly.
  • Ordering: when both on_retry and on_give_up are configured, on_retry still runs first for the final rescued exception. This preserves existing on_retry semantics (it runs whenever Retriable rescues a retriable exception).
  • Non-firing cases: the callback does not fire when the raised exception is not in :on, nor when :retry_if returns false. Both are immediate re-raises, not retry exhaustion.
  • Opt-out: pass on_give_up: false (or nil) to suppress a configured handler for a single call, mirroring on_retry's existing semantics.
  • Handler errors: an exception raised inside on_give_up propagates and replaces the original retried exception (same policy as on_retry, now documented).
  • Elapsed time: elapsed_time is re-read after on_retry returns so handler-induced delay counts toward the max_elapsed_time budget for the give-up decision.

Implementation

  • New on_give_up attribute on Config::ATTRIBUTES (default nil). Threads through configure, per-call options, with_context, with_override, and per-context with_override via the existing ATTRIBUTES plumbing.
  • can_retry? refactored into retry_stop_reason, returning the reason symbol or nil. Cleaner because it folds "should we stop?" and "why?" into a single decision point.
  • call_on_give_up helper mirrors call_on_retry, including the false/nil short-circuit.
  • Rebased onto 4.x; the callback path uses the Ruby 3+/4.0 retry loop without the removed timeout: plumbing.
  • README: new on_give_up subsection in Callbacks; options-table row; explicit documentation of non-firing cases, handler-raises behavior, and an extended Contexts example.
  • CHANGELOG: HEAD entry covering signature, reasons, non-firing cases, and the opt-out.
  • .rubocop.yml: bump Naming/MethodParameterName.MinNameLength to 2 so existing single-letter params (on, e) remain acceptable in the new helper signatures.

Test Plan

  • bundle exec rspec — 143 examples, 0 failures.
  • bundle exec rubocop lib spec — 11 files inspected, no offenses detected.

Coverage includes:

  • Both reasons (:tries_exhausted, :max_elapsed_time) with full argument-shape assertions.
  • Non-firing paths: block succeeds, exception not in :on, retry_if rejects, and hash :on message mismatch.
  • Explicit opt-out via on_give_up: false.
  • Ordering: on_retry runs before on_give_up for the final exception.
  • Threading: per-call option, with_context, top-level with_override, per-context with_override, and Kernel#retriable delegation.
  • Handler that raises replaces the original exception.

Comment thread lib/retriable.rb Outdated
kamui added a commit that referenced this pull request May 26, 2026
- README: document non-firing cases (non-retriable exceptions and
  retry_if rejection) and handler-raised-error propagation semantics.
- README: extend the :aws context example with on_give_up.
- CHANGELOG: include the full callback signature, reason symbols, and
  the false/nil opt-out in the HEAD entry.
- Specs: cover Retriable.override(contexts:) dispatch of on_give_up,
  kernel-extension delegation of on_give_up, and the policy that an
  exception raised inside on_give_up replaces the original.

Builds on feat/on-give-up-callback (PR #127, issue #72). No library
code changes; existing implementation already satisfies the behavior.
@kamui kamui force-pushed the feat/on-give-up-callback branch 2 times, most recently from 929d0e5 to f516ede Compare May 26, 2026 21:24
@kamui kamui force-pushed the feat/on-give-up-callback branch from f516ede to 107ed03 Compare May 27, 2026 02:08
Add an on_give_up callback that runs when Retriable stops retrying after a rescued retriable exception. The callback receives the exception, try number, elapsed time, next interval, and a reason symbol (:tries_exhausted or :max_elapsed_time).

This covers both final-failure callbacks and max_elapsed_time observability, while preserving on_retry ordering and opt-out semantics with on_give_up: false. Thread the option through config, local options, contexts, with_override, and the kernel extension. Document the API and add coverage for firing paths, non-firing paths, context/override plumbing, and handler error behavior.

Closes #72.
Closes #76.
@kamui kamui force-pushed the feat/on-give-up-callback branch from 107ed03 to 913cec0 Compare May 27, 2026 04:44
@kamui kamui changed the base branch from main to 4.x May 27, 2026 04:45
@kamui kamui marked this pull request as ready for review May 27, 2026 04:53
@kamui kamui merged commit ade4cf0 into 4.x May 27, 2026
1 check passed
@kamui kamui deleted the feat/on-give-up-callback branch May 27, 2026 05:00
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.

Callback if max elapsed time has been reached Have a parameter to supply a proc that is only called on the final failure

1 participant