fix: allow lazy load evaluations when $inited key is not set#508
Draft
kinyoklion wants to merge 2 commits intomainfrom
Draft
fix: allow lazy load evaluations when $inited key is not set#508kinyoklion wants to merge 2 commits intomainfrom
kinyoklion wants to merge 2 commits intomainfrom
Conversation
In lazy load / daemon mode, the SDK's Initialized() check was blocking all flag evaluations when the $inited key was not found in the persistent store. This is problematic because in daemon mode, an external process (like Relay Proxy) populates the store, and the $inited key may not always be present. The fix changes LazyLoad::Initialized() to always return true, allowing evaluations to proceed using available data. When the underlying source reports not initialized ($inited key not found), a warning is logged to alert operators that a Relay Proxy or other SDK should set this key. This aligns with the Go SDK behavior where daemon mode (ExternalUpdatesOnly) always considers the data source initialized. Updated unit tests to reflect the new behavior and added tests verifying the warning is logged appropriately. Co-Authored-By: rlamb@launchdarkly.com <kingdewman@gmail.com>
Contributor
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Reworked approach based on review feedback: Initialized() should return false when $inited is not set (consistent with other SDK implementations), and the evaluation path should handle this case by warning and proceeding rather than blocking. Changes: - Added CanEvaluateWhenNotInitialized() virtual method to IDataSystem interface (defaults to false) - LazyLoad overrides to return true (can serve on demand) - PreEvaluationChecks warns and proceeds when data system can evaluate while not initialized, instead of returning CLIENT_NOT_READY - AllFlagsState similarly warns and proceeds instead of returning empty - Reverted LazyLoad::Initialized() to original behavior (truthfully reports whether $inited key exists) - Added unit test for CanEvaluateWhenNotInitialized() This matches the pattern used in the Erlang SDK where the evaluation path distinguishes between 'not initialized' (blocks) and 'store initialized' (warns but proceeds). Co-Authored-By: rlamb@launchdarkly.com <kingdewman@gmail.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.
Summary
In lazy load / daemon mode,
ClientImpl::PreEvaluationChecksgates all flag evaluations onInitialized(). ForLazyLoad,Initialized()checks whether the$initedkey exists in the persistent store (e.g. Redis). In daemon mode, an external process (Relay Proxy, another SDK) populates the store, but the$initedkey may not always be present — causing every evaluation to returnCLIENT_NOT_READYeven though flag data is available for on-demand fetching.This PR introduces a
CanEvaluateWhenNotInitialized()virtual method onIDataSystem(defaults tofalse).LazyLoadoverrides it to returntrue, since it can always fetch data on demand. The evaluation path (PreEvaluationChecksandAllFlagsState) now checks this method: when the data system reports it can evaluate while not initialized, a warning is logged and evaluation proceeds instead of blocking.LazyLoad::Initialized()continues to truthfully report whether$initedis set — consistent with other SDK implementations. The behavioral change is in the evaluation path, not the initialization reporting.Files changed:
idata_system.hpp— addsCanEvaluateWhenNotInitialized()virtual method (defaultfalse)lazy_load_system.hpp— overridesCanEvaluateWhenNotInitialized()to returntrueclient_impl.cpp—PreEvaluationChecksandAllFlagsStatewarn-and-proceed when data system can evaluate while not initializedlazy_load_system_test.cpp— adds test forCanEvaluateWhenNotInitialized()Review & Testing Checklist for Human
PreEvaluationCheckslogs a warning on every evaluation call when$initedis missing. There is no rate-limiting or "log once" guard. In a busy daemon-mode deployment without$inited, this could produce extremely noisy logs. Consider whether a once-per-session or rate-limited warning is more appropriate.StartAsync()behavior:LazyLoad::Initialize()only setskValidifInitialized()returnstrue. When$initedis absent, status stays atkInitializingand theStartAsync()future may never resolve. Verify this is acceptable — evaluations proceed (via the new warning path), but the client may never report as fully "started."AllFlagsStatewhen store is empty/unreachable: Previously returned{}immediately when not initialized. Now for LazyLoad it proceeds to callAllFlags()/AllSegments()on the store. Verify behavior is reasonable if the store is genuinely empty vs. just missing$inited.Notes
not_initialized(blocks) vsstore_initialized(warns but proceeds).NullDataSourcethat always reports initialized.Initialized()gating issue.Link to Devin session | Requested by: @kinyoklion