Evaluate checkFlags from the cache when the replicator is not ready - #201
Closed
ryanechternacht wants to merge 1 commit into
Closed
ryanechternacht wants to merge 1 commit into
ryanechternacht wants to merge 1 commit into
Conversation
checkFlags only took the DataStream path when isConnected() was true. In replicator mode isConnected() is the health endpoint's ready field, which goes false when Schematic is unreachable or the account is closed even though the replicator's Redis cache is intact. checkFlags then skipped the cache, called the API, and returned flag defaults for every key when that failed. checkFlag has no such gate, so the two disagreed. Drop the isConnected() gate so checkFlags evaluates locally whenever a DataStream client exists, matching checkFlag and the Go SDK. In WebSocket mode a disconnected client still evaluates entities it has cached and throws for anything it would need to fetch, which sends the whole set to the API as before. Add a replicator mode test with a real DataStream client, fake Redis seeded in the replicator's key layout, the real WASM engine, and a health endpoint reporting ready: false. checkFlags returns the evaluated values and never calls the API. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Sep 29, 2026
bpapillon
approved these changes
Sep 29, 2026
Member
Author
|
Closing in favor of fixing this in the Replicator. The SDK is right to gate flag checks on Replicator readiness; the Replicator should keep reporting |
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.
Problem
In replicator mode,
datastreamClient.isConnected()returns the replicator health endpoint'sreadyfield. When a customer's Schematic account is closed or Schematic is unreachable, the replicator stays up and keeps its Redis cache, but reportsready: false.checkFlagswith keys only took the DataStream path whenisConnected()was true. With the replicator not ready it skipped the cache, calledfeatures.checkFlagson the API, and when that failed returned flag defaults for every key.checkFlaghas no such gate and keeps evaluating from Redis, so the single and bulk checks gave different answers for the same flag.What I found
CheckFlagsinclient/schematic_client.gogoes to the datastream wheneveruseDataStream()is true, andresolveEntitiesindatastream/client.goreturns whatever the cache holds in replicator mode.checkFlagsViaDataStreamloops overdatastreamClient.checkFlag, and the replicator branch of that method evaluates from the cache without a readiness check. The Node datastream client has no separate bulk path (Go'sevaluateBulkhas no Node equivalent), so there is no other gate to remove.Change
checkFlagsnow takes the DataStream path whenever a DataStream client exists and keys were passed. TheisConnected()condition is gone, in both modes.For WebSocket mode this is the same behavior
checkFlagalready has and matches Go: a disconnected client evaluates entities it has cached, and throws for any flag or entity it would need to fetch.checkFlagsViaDataStreamreturns null on the first throw, so the whole set still goes to the API in that case.Test
New
tests/unit/replicator/check-flags-not-ready.test.ts(and a.fernignoreentry for the directory). It uses a real DataStream client in replicator mode, the real WASM rules engine, and the in-memory fake Redis seeded the way the replicator writes it (snake_case JSON under versioned keys).fetchis stubbed so the health endpoint returns{ ready: false, cache_version: "v-test" }.checkFlagsfor a metric-gated flag and an always-on flag, both defaulting to false, returnstruefor each with the cached company's ID, and neitherfeatures.checkFlagsnorfeatures.checkFlagis called.checkFlagandcheckFlagsagree for the same flag.Both tests fail on main (every key comes back as its default) and pass with this change.
yarn buildandyarn testpass (101 suites; the Redis integration suite is skipped locally withoutTEST_REDIS_URL).🤖 Generated with Claude Code