Real-Time Synchronization
Server-Sent Events (SSE) continuously stream configuration updates from SOASAP Cloud to connected SDKs.
Introduction
SOASAP separates synchronization from evaluation. Applications evaluate flags locally from an in-memory snapshot; configuration updates arrive through a background synchronization channel that does not participate in the request path.
SOASAP uses Server-Sent Events (SSE) to stream updates from SOASAP Cloud to SDKs in near real time. When an operator changes a flag in the dashboard, connected SDKs receive the update without a redeploy, restart, or application-initiated poll.
Evaluation remains local. Flag getters never wait on SSE. Synchronization keeps the snapshot current. The background worker applies incoming events so future evaluations return updated values.
Why real-time synchronization exists
Feature flags are only useful if configuration changes reach running applications quickly. Without push-based synchronization, SDKs must poll the control plane on a fixed interval.
Polling-based configuration has predictable drawbacks:
- Delayed changes — updates propagate only as fast as the poll interval allows
- Slower kill switches — disabling a broken feature waits on the next poll cycle
- Rollout coupling — gradual enablement depends on how often each instance polls
- Wasted resources — repeated HTTP requests download unchanged configuration
- Operational blind spots — different instances may run different values until their polls align
SOASAP uses event-driven synchronization instead. The control plane pushes updates when configuration changes; SDKs apply them in the background while evaluation continues from memory.
Synchronization flow
When a flag changes:
- Configuration is updated in SOASAP Cloud for the target environment
- A synchronization event is generated and published to connected SSE subscribers
- Connected SDKs receive the event on their long-lived background connection
- The SDK validates the payload and updates the local snapshot atomically
- Future evaluations return the updated value from memory
No redeploy is required. No process restart is required. Applications already running continue serving traffic; only subsequent flag reads observe the new configuration.
On initial connection, the SDK receives a full environment snapshot to establish a consistent baseline. Subsequent events refresh that snapshot as configuration evolves.
Server-Sent Events (SSE)
SOASAP uses SSE rather than request polling for configuration delivery. SSE is a standard HTTP mechanism for one-way, server-to-client streaming.
- Long-lived HTTP connection — the SDK opens a persistent connection to SOASAP Cloud at startup (or when preload starts the background worker)
- One-way event stream — the server pushes configuration events; the SDK does not send flag read requests over this channel
- Lightweight protocol — SSE runs over standard HTTPS with simple text-framed events, without a custom binary protocol
- Efficient resource usage — one connection per SDK instance replaces repeated polling requests across the fleet
SSE is a good fit for configuration updates because changes are infrequent relative to flag reads, updates flow in one direction, and clients need low-latency notification without blocking application threads. The control plane sends periodic heartbeat comments on idle connections to keep intermediaries from timing out long-lived streams.
Evaluation and SSE are separate threads of execution. A slow or blocked SSE connection does not
delay GetBool, getBool, or equivalent
getter calls.
Delta updates
SOASAP avoids the polling model where applications repeatedly download configuration on a timer regardless of whether anything changed. Instead, the control plane pushes update events only when configuration changes.
Update payloads are scoped to the SDK's bound environment. SDKs receive compact JSON documents over SSE — either a full environment snapshot or an incremental delta containing changed flag data. The SDK validates each payload and applies it without initiating a separate fetch per flag read.
Compared to periodic full-config polling, push-based updates provide:
- Reduced bandwidth — no repeated downloads of unchanged configuration across the fleet
- Faster propagation — changes are delivered as events rather than waiting for the next poll interval
- Lower CPU usage — the SDK applies validated payloads in a background worker, not on every request
- Lower memory pressure — atomic snapshot replacement avoids duplicate parsing on the hot path
Wire format details are handled by the SDK. Applications interact only with getters and defaults — not with SSE parsing or payload merging.
Update latency
On healthy networks, connected SDKs typically receive updates within milliseconds to sub-second timeframes after a dashboard save. Propagation is event-driven: the change is pushed as soon as SOASAP Cloud processes it and the SDK's SSE connection is active.
Exact propagation time depends on factors outside SOASAP's read path:
- Network conditions between the SDK host and SOASAP Cloud
- Client connectivity — whether the SSE connection is currently established
- Runtime scheduling — background worker thread availability on the host
- Intermediate proxies, load balancers, or firewalls that buffer or delay long-lived connections
SOASAP does not guarantee a specific end-to-end latency SLA for configuration propagation. Treat sub-second delivery as typical on healthy networks, not as a hard upper bound. Monitor synchronization health separately from request latency. See Flag Not Updating.
Atomic snapshot updates
SDKs replace snapshots atomically. Readers never observe partially applied state — a getter always reads either the previous complete snapshot or the new complete snapshot, never a mix of old and new flag values.
Implementation varies by platform — for example, .NET SDKs use Interlocked.Exchange
for lock-free snapshot swaps; Kotlin uses AtomicReference. The
invariant is the same: concurrent readers on the request path continue against the previous
snapshot until the swap completes, then immediately see the new snapshot.
Invalid payloads are ignored; the snapshot remains unchanged. Applications continue evaluating against the last known good configuration.
Applications always read a consistent view of configuration at the moment of each getter call.
Reconnect behavior
SSE connections are long-lived but not permanent. Connections may disconnect because of:
- Network interruptions — transient packet loss, Wi-Fi handoff, mobile network changes
- Process restarts — deploys, pod rescheduling, application crashes
- Infrastructure maintenance — load balancer rotation, control plane upgrades
- Temporary outages — SOASAP Cloud unavailability or DNS failures
- Proxy timeouts — corporate proxies or gateways closing idle connections
SDKs automatically reconnect using exponential backoff. No application code is required to trigger reconnection — the background worker handles connect, disconnect, and retry independently of flag evaluation.
On reconnect, the SDK re-establishes the SSE stream and receives a current environment snapshot. Catch-up logic ensures updates published while the connection was down are not permanently lost once connectivity returns.
Configure OnError / onError handlers
to log synchronization failures without affecting reads. See
SSE Disconnected.
What happens during disconnects
Evaluation does not stop when SSE disconnects. Applications continue using the last known snapshot held in memory — the same O(1) lookup path as when the connection is healthy.
Only synchronization is affected. Dashboard changes made during a disconnect are not reflected until the SDK reconnects and receives updated events. Existing flag values remain available locally throughout the outage.
See Offline Operation.
Relationship to local evaluation
Local Evaluation and Real-Time Synchronization solve different problems. Both are required for a production-ready feature flag system — neither replaces the other.
| Concern | Mechanism | When it runs |
|---|---|---|
| Low-latency reads | Local Evaluation | On every getter call — synchronous, in-process |
| Current configuration | Real-Time Synchronization | Background — SSE worker, asynchronous |
Synchronization feeds the snapshot; evaluation consumes it. Without synchronization, snapshots become stale after dashboard changes. Without local evaluation, every read would depend on network availability and control plane latency.
Persistent Cache extends this model across restarts — disk restores the last snapshot before SSE reconnects. Default Values cover the gap when no snapshot or key exists yet.
Common misconceptions
"Flag reads use SSE"
False. SSE updates the snapshot in the background. Flag reads use local memory only. No getter opens the SSE connection or waits on stream delivery.
"Applications stop working if SSE disconnects"
False. Evaluation continues from the last known snapshot. Only the delivery of new configuration is paused until reconnect.
"The SDK polls SOASAP every few seconds"
False. SOASAP uses event-driven synchronization over a persistent SSE connection. The SDK does not poll on a timer to detect configuration changes.
"Every dashboard change requires a restart"
False. Changes propagate automatically to connected SDKs. Running processes pick up new values on the next flag read after the snapshot is updated — no redeploy or restart required.
"Synchronization failures should fail requests"
False. Synchronization errors are reported through background error handlers. Request handlers should not fail because SSE is disconnected — they should continue with the last known snapshot and explicit defaults.
Production recommendations
- Monitor synchronization health — alert on prolonged SSE disconnects, repeated
OnErrorcallbacks, and stale configuration age; application HTTP health checks can pass while sync is degraded. - Allow outbound HTTPS connections — SDK hosts must reach SOASAP Cloud for SSE; corporate firewalls and proxies must permit long-lived
text/event-streamconnections without buffering that blocks delivery. - Use preload where supported — start the SSE background worker at startup (
PreloadFlags(),preload: true) so synchronization begins before traffic arrives. See Non-Blocking Startup. - Handle prolonged disconnects through observability — log sync errors, track time since last successful update, and define operational runbooks for extended outages; reads continue but configuration freezes at the last snapshot.
- Treat synchronization and evaluation as separate concerns — do not block request handlers on sync status; do not conflate application availability with configuration freshness.
Related documentation
- Local Evaluation — O(1) flag reads from memory with no network on the request path
- Persistent Cache — snapshot restoration across restarts before SSE reconnects
- Offline Operation — evaluation behavior when sync is unavailable
- Default Values — safe fallbacks when the snapshot cannot supply a valid value
- Non-Blocking Startup — starting SSE without blocking host startup
- Production Safety — kill switches, defaults, and environment isolation
- SDK Documentation — install and configure your platform SDK