feat: real-time streaming sync over WebSocket (opt-in) - #5
Merged
Conversation
Adds opt-in WebSocket streaming as an alternative to polling, modeled on FeatBit's JS/RN SDK and the evaluation server's /streaming wire protocol. Polling remains the default. - StreamingDataSynchronizer: OkHttp WebSocket to /streaming?type=client&version=2&token=…; sends data-sync(user,timestamp), applies full/patch flag pushes into the shared store, app-level ping heartbeat, exponential-backoff reconnect - ConnectionToken: port of FeatBit's token scheme (secret+timestamp), verified by a round-trip unit test against a faithful port of the server decoder - FBOptions.streaming(wsUri) + DataSyncMode.Streaming; FBClientImpl wires the new mode - Reuses store/evaluator/FlagTracker/flagChanges unchanged - Rethrow CancellationException in TrackInsight (clean shutdown, no spurious error logs) - README: document both modes; clarify lineage (.NET-based; streaming from JS/RN protocol) Verified end-to-end against a real FeatBit server (Testcontainers): streaming client connects, evaluates a seeded flag, and receives a server-side toggle as a real-time push. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds opt-in WebSocket streaming as an alternative to polling, so flag changes arrive in real time. Polling stays the default; this is purely additive (the
DataSynchronizerabstraction was built for it).Lineage note
The SDK started as a port of FeatBit's .NET client SDK (polling, store, evaluator, tracker, insights, API). The .NET client SDK is polling-only, so streaming is modeled on FeatBit's JS/RN SDK and the evaluation server's
/streamingwire protocol (read fromfeatbit/featbit). README/intro updated to reflect this.What's added
StreamingDataSynchronizer— OkHttp WebSocket to/streaming?type=client&version=2&token=…:data-syncwith the user + last timestamp; appliesfull/patchflag pushes into the same in-memory store (so evaluation,FlagTracker, andflagChangesare identical to polling)pingheartbeat + exponential-backoff reconnect (fresh token per connect; server expires tokens in ~30s)ConnectionToken— port of FeatBit's token scheme (secret + timestamp), verified by a round-trip unit test against a faithful port of the server's decoderFBOptions.streaming(wsUri)+DataSyncMode.Streaming;FBClientImplwires the new modeCancellationExceptioninTrackInsight→ clean shutdown (no spurious error logs)Usage
Verification (against a real FeatBit server via Testcontainers)
FeatBitStreamingE2ETest(gated byFEATBIT_E2E=1): a real streamingFBClientconnects, evaluates a seeded flag (true), and receives a server-side toggle as a real-time push (test body ~0.5s).Mobile note
WebSockets get killed in background/doze. README recommends streaming while foregrounded + reconnect on resume/network; polling remains available as a fallback. A lifecycle-aware auto-switch could be a future addition.
🤖 Generated with Claude Code