Why did my flag change take minutes to reach my app?
Last updated:
Streaming delivers a flag change within seconds, so anything slower is not coming over the stream. When the stream cannot connect, most SDKs give up after five failed attempts and poll instead, every thirty seconds by default. A stream held open by a buffering proxy goes quiet without raising an error, so the SDK keeps waiting on a connection that delivers nothing.
A flag change should reach a connected SDK in seconds. When it takes longer, the shape of the delay tells you what happened.
Up to thirty seconds of lag, every time, means the SDK is picking changes up on its default poll interval instead of the stream. If the change only ever lands when the process restarts, nothing is refreshing at all.
Why the stream drops
When the stream cannot connect, the SDK retries on its own and waits a little longer after each failure, up to thirty seconds. Most SDKs stop after five failures in a row and switch to polling, which is where the steady half-minute lag comes from. Node logs it: SSE connection failed after 5 retries, falling back to polling.
Only outright failures count. A connection that gets its first snapshot through resets the tally, so an HTTP client that applies its overall timeout to a long-lived stream causes churn and never reaches the fallback. Set it to abort any request after ten seconds and it tears the stream down on schedule, with the SDK reconnecting and picking up a full snapshot each time. We shipped exactly this bug in our own C# SDK once.
Reverse proxies and some corporate egress paths hold a response until it completes, and a stream never completes, so nothing gets through, not even the ping the server sends every thirty seconds. No error reaches the SDK either. The C#, Java, Python and Ruby SDKs close a stream after ninety seconds of silence and try again.
Confirming which one you have
Turn streaming off and watch the next change.
import { FeatureflipClient } from '@featureflip/node';
// Streaming on (the default): changes arrive in secondsconst client = FeatureflipClient.get({ sdkKey, streaming: true });
// Streaming off: changes arrive on the poll interval insteadconst client = FeatureflipClient.get({ sdkKey, streaming: false, pollInterval: 30_000 });If it lands within one poll interval, your key and the service are both fine, and the stream is the only thing left that can be failing.
A healthy stream is the SDK’s only update path. The polling fallback waits for a stream that keeps failing, and one that connects and then carries nothing never fails in that sense, so the SDK keeps serving the last snapshot it received.
The fix
Give the streaming connection its own timeout settings instead of letting it inherit your general HTTP client’s, and make sure nothing in the path buffers responses. If the network you run in will not hold a stream open, turn streaming off and pick a poll interval you can design around. Restart the process after either change so the SDK starts on a fresh connection.
Related questions
Why does my flag flash the wrong value on load?
A client SDK serves your default until its first payload arrives. The flash is that gap becoming visible, and rendering around it closes the gap for good.
Why does my flag work in dev but not production?
Flags are configured per environment, so enabling one in development changes nothing elsewhere. Rules and rollout percentages are per environment too.
Why is my feature flag returning the default value?
Six reasons a Featureflip flag falls back to the default you passed, ordered by how often each one is the real cause, with the check for each.
Still stuck?
The docs cover every SDK, and the free Solo plan is enough to reproduce most of these locally.