Skip to content

refactor!: share one exponential backoff calculation - #1646

Open
spydon wants to merge 2 commits into
breaking/shared-http-methodfrom
breaking/shared-exponential-backoff
Open

refactor!: share one exponential backoff calculation#1646
spydon wants to merge 2 commits into
breaking/shared-http-methodfrom
breaking/shared-exponential-backoff

Conversation

@spydon

@spydon spydon commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Tier 3 of #1572, third of four PRs. Stacked on #1645 (which is stacked on #1644).

What

The same "double the delay, cap it" math existed in three places:

Site Before
RetryOptions.delay (supabase_common) delayFactor * pow(2, min(attempt, 31)) * jitter, capped at maxDelay
RetryTimer.createRetryFunction (realtime_client) firstDelay << min(tries - 1, maxShift), capped at maxDelay, in milliseconds
PostgrestBuilder._defaultRetryDelay Duration(seconds: min(pow(2, attempt), 30))

All three now call one helper in supabase_common:

Duration exponentialBackoff(
  int attempt, {
  required Duration initialDelay,
  required Duration maxDelay,
  double randomizationFactor = 0,
  Random? random,
});

attempt is zero based, so attempt 0 waits initialDelay and each attempt after that doubles until maxDelay. Jitter is opt-in per caller, since only the storage upload retry uses it today.

No behaviour change

Each call site keeps the delays it had:

  • realtime keeps its one-based tries and its millisecond return type, so RealtimeClient(reconnectAfterMs: ...) and the TimerCalculation typedef are untouched. It just passes tries - 1 to the helper.
  • RetryOptions.delay keeps returning Duration.zero for attempt 0 and keeps its jitter.
  • postgrest still starts at one second and caps at thirty.

maxShift (a public top-level const in realtime_client) is removed: the exponent clamp that stops the doubling from overflowing now lives with the shared calculation. It was not registered in the compliance matrix.

Realtime's millisecond-based options (reconnectAfterMs, heartbeatIntervalMs, longpollerTimeout) would read better as Durations, but converting them is a separate change; doing only reconnectAfterMs here would leave that API half converted.

Testing

New backoff_test.dart covers the start delay, the doubling, the cap, the absence of jitter by default and the jitter bounds with an injected Random. realtime_client's existing retry_timer_test.dart and postgrest's retry_test.dart pass unchanged, which is the real check that the delays did not move.

melos analyze and melos format clean; gotrue, postgrest, storage_client, realtime_client, supabase and supabase_common suites pass against the local stack. Capability matrix symbol and drift checks pass.

@spydon
spydon requested a review from a team as a code owner August 5, 2026 09:47
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0dfec23b-f9b9-4894-b01c-ba38fba4cc69

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@spydon spydon changed the title refactor: share one exponential backoff calculation refactor!: share one exponential backoff calculation Aug 5, 2026
spydon added 2 commits August 5, 2026 17:08
Three copies of the same doubling-with-a-cap math lived in the repo:
`RetryOptions.delay` in supabase_common, realtime's
`RetryTimer.createRetryFunction` and postgrest's default retry delay. They
now all call `exponentialBackoff` in supabase_common, which takes a zero
based attempt, doubles from `initialDelay` and caps at `maxDelay`, with
optional jitter.

The three call sites keep their existing delays: realtime still counts
`tries` from one and returns milliseconds, `RetryOptions` still treats
attempt zero as no delay, and postgrest still starts at one second and caps
at thirty.

`maxShift` in realtime_client is gone; the exponent clamp that kept the
doubling from overflowing now lives with the shared calculation.

Part of #1572 (tier 3), under the v3 umbrella #1278.
@spydon
spydon force-pushed the breaking/shared-http-method branch from 9a136d8 to 4b05226 Compare August 5, 2026 15:14
@spydon
spydon force-pushed the breaking/shared-exponential-backoff branch from c2b1b6c to 549c593 Compare August 5, 2026 15:15
@spydon spydon added the v3 label Aug 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants