Skip to content

fix(events): back delivery off from an extended initial delay after a refusal - #425

Open
abelonogov-ld wants to merge 1 commit into
andrey/event-durability-tier3-persistencefrom
andrey/delivery-retry-extended-initial-delay
Open

abelonogov-ld wants to merge 1 commit into
andrey/event-durability-tier3-persistencefrom
andrey/delivery-retry-extended-initial-delay

Conversation

@abelonogov-ld

@abelonogov-ld abelonogov-ld commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Makes event delivery's backoff conform to RETRY 1.5.6: once an unexpected failure (a 401, 403 or other non-retryable 4xx) has been seen, the backoff is computed from a separate extended initial delay, until an accepted delivery resets it.

Stacked on #408 (tier 3).

Delivery used to reach the same first wait by keeping a 1 second base and raising the attempt count to at least 10 on a refusal (2⁹ s = 512 s). That matches RETRY's waits except for one case: a refusal after ten or more ordinary failures in a row overshot, waiting 1024 s or more rather than 512 s.

  • DeliveryRetryState binds EXTENDED_INITIAL_DELAY_MILLIS = 512 s (about 8.5 minutes, the same first wait as before) in place of ATTEMPTS_AFTER_UNEXPECTED.
  • The first refusal since a reset enters the extended regime with the attempt count at 1, as StreamingRetryState does. Later failures of either kind add 1 and keep the extended base and ceiling until a reset.
  • The extended delays are floored at the initial delay (RETRY 1.5.4.1).
  • retryDelaysForTesting takes the extended initial delay too. Each test passes the first refusal wait it got before, so no test's timing changes.
  • New tests: a refusal after 12 ordinary failures waits 512 s; extended delays bound below the initial delay are raised to it.

The waits for every sequence the existing tests cover are unchanged: 1, 2, 4… s up to the flush interval for ordinary failures; 512, 1024, 2048, then 3600 s for repeated refusals.

Tested: :launchdarkly-android-client-sdk:testDebugUnitTest, 1259 tests, 0 failures.


Note

Overview
Event delivery backoff after unexpected failures (e.g. 401) no longer fakes the ~8.5 minute first wait by jumping the attempt count to 10. DeliveryRetryState now uses an extended regime: the first refusal since a successful delivery sets inExtendedRegime and resets attempts to 1, then waits are computed from EXTENDED_INITIAL_DELAY_MILLIS (512s) with the extended ceiling, matching RETRY 1.5.6 and avoiding overshoot when many ordinary failures precede a refusal.

Extended initial/ceiling delays are clamped to at least the normal initial delay (RETRY 1.5.4.1). ComponentsImpl.retryDelaysForTesting and DeliveryRetryState’s constructor take a configurable extended initial delay; tests pass explicit values so existing timing expectations stay the same, plus new cases for refusal-after-many-ordinary-failures and inverted delay bounds.

Reviewed by Cursor Bugbot for commit 95fe680. Bugbot is set up for automated code reviews on this repo. Configure here.

RETRY 1.5.6 makes the extended initial delay the base of the backoff once
an unexpected failure is seen. Delivery reached the same first wait by
raising the attempt count to at least 10 on a 1 s base, which a refusal
after ten or more ordinary failures overshot. Bind the extended initial
delay to 512 s, start the count at 1 on the first refusal since a reset,
and floor the extended delays at the initial delay (RETRY 1.5.4.1).

Matches the iOS change.

Co-authored-by: Cursor <cursoragent@cursor.com>

This branch has not been deployed

No deployments
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