Skip to main content

What the client holds

One bulk GET /v1/sync returns every config and flag the key can see, and the client keeps that snapshot in memory. Reads are served from it - they never touch the network and never block.

When it refreshes

While the live stream is connected the effective TTL is at least 60 seconds: updates already arrive by push, so polling on top of it would be redundant.

A read never waits

A read past the TTL starts a refresh and returns the snapshot it already has. This is deliberate: a component rendering a flag should not be blocked on a network round trip, and a value a few seconds old is almost always the right answer. The refresh replaces the snapshot when it lands, and everything bound to it updates.

Concurrent refreshes are one request

An event burst, a TTL expiry and an explicit sync arriving together produce a single request. Every caller shares it, and a response is applied only if no newer one has already been applied - so a slow reply cannot overwrite fresher data.

ETag

Each snapshot carries the server’s ETag, sent back as If-None-Match. When nothing has changed the server answers 304 Not Modified and no data is transferred. A 304 is a successful sync: it renews the TTL and clears any degraded state, exactly as a 200 does.

Large numbers

An integer a double cannot represent exactly - above 2^53 - is decoded as a bigint rather than silently rounded. Order ids, amounts in minor units and nanosecond timestamps survive intact. Every value a double holds exactly stays a number, so arithmetic on ordinary config values is unchanged.

When the server pushes back

Throughout all of these, reads keep returning the last good snapshot.

Releasing the client

Tearing down the client releases the stream, every timer and every listener, and is final - a refresh already in flight cannot re-arm anything afterwards. The framework integration does this for you when the component tree or application is destroyed.