-
Notifications
You must be signed in to change notification settings - Fork 4
Description
Problem
OFREP static-context providers currently poll on a fixed timer by default (JS: 30s, Swift: 30s, Kotlin: 5min). This has two issues:
-
Sticky bucketing — polling causes flag values to change mid-session, which breaks the expectation that a user sees consistent behavior throughout a session. Most platforms expect bucketing to remain sticky for a user's whole session.
-
Resource efficiency — timer-based polling is wasteful for static-context providers where the evaluation context rarely changes during a session. This is especially problematic on mobile where it impacts battery life and data usage.
This is out of step with how vendor SDKs handle client-side refresh. DevCycle, LaunchDarkly, Statsig, and Eppo do not use timer-based polling as the default client-side refresh mechanism:
| Vendor | Default Mechanism | Timer Polling? |
|---|---|---|
| DevCycle | Init + context change + foreground + SSE push | No |
| LaunchDarkly | SSE streaming foreground, 60min poll background only | No (streams) |
| Statsig | Init + user change only | No |
| Eppo | Init only, polling opt-in | No (off by default) |
| ConfigCat | Auto polling (60s) | Yes |
| Unleash | Polling (30s) | Yes |
Proposed Solution
Replace default timer-based polling with event-driven refresh for static-context providers. Providers should re-fetch bulk evaluations on:
- Initialization (already defined in ADR-0009)
- Context change (already handled via
onContextChange) - App foreground / page visibility — re-fetch when the app returns from background or the page becomes visible
Timer-based polling should remain available as an opt-in for applications that want it, but default to disabled.
Further details on foreground detection, debouncing, and interaction with SSE (see #62) will follow in an ADR PR.