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:

  1. Configuration is updated in SOASAP Cloud for the target environment
  2. A synchronization event is generated and published to connected SSE subscribers
  3. Connected SDKs receive the event on their long-lived background connection
  4. The SDK validates the payload and updates the local snapshot atomically
  5. 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.

Architectural principle. Reads are decoupled from sync. A disconnected SSE stream delays future updates — it does not block, fail, or slow flag evaluation. Stale configuration is preferable to unavailable configuration.

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 OnError callbacks, 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-stream connections 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