Implement flags persistence, reset on reload, and web parity & bugfixes#432
Open
efahk wants to merge 13 commits into
Open
Implement flags persistence, reset on reload, and web parity & bugfixes#432efahk wants to merge 13 commits into
efahk wants to merge 13 commits into
Conversation
Confidence Score: 5/5Safe to merge; the race-condition fixes and persistence layer are well-guarded, and the native bridges are additive changes behind an updated SDK version. The critical correctness fixes (promise identity guard, updateContext invalidation, areFlagsReady TTL check) are all present and well-tested. The new persistence layer round-trips correctly and isolates data per token and distinct_id. The remaining findings are style/consistency concerns that do not affect correctness. javascript/mixpanel-flags-js.js deserves a second look on the getVariant()/getAllVariants() error-path inconsistency and the redundant staleness check.
|
| Filename | Overview |
|---|---|
| javascript/mixpanel-flags-js.js | Core JS-fallback implementation: adds fetch promise identity guard to prevent stale writes, fixes updateContext() to invalidate in-flight fetches, and areFlagsReady() now checks TTL staleness. Minor: redundant double-staleness check in getVariant(). |
| javascript/mixpanel-flag-persistence.js | New persistence layer: serializes/deserializes flag variants with TTL and distinct_id scoping. Policies are cleanly separated. save/load round-trip is consistent. |
| javascript/mixpanel-flags.js | Facade class updated: adds getAllVariants/Sync, removes areFlagsReadySync guard before native delegate calls, updateContext no longer throws in native mode. MixpanelFlagsJS always constructed on access even when flags not enabled. |
| index.js | reset() now chains flags.reset() in the .then() callback so JS-mode flags are cleared only after native reset succeeds. Fire-and-forget pattern is intentional per prior review thread. |
| ios/MixpanelReactNative.swift | Adds getAllVariants/Sync and updateFlagsContext bridge methods. updateFlagsContext calls flags.setContext() which always merges; replace semantics are not forwarded (documented limitation). |
| android/src/main/java/com/mixpanel/reactnative/MixpanelReactNativeModule.java | Adds getAllVariants/Sync and updateFlagsContext bridge methods matching iOS. options.replace is not forwarded to setContext (same documented limitation as iOS). |
| MixpanelReactNative.podspec | Bumps Mixpanel-swift dependency from 5.1.3 to 6.5.0 to pick up native flags persistence and reset support. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[getVariant called] --> B[await persistenceLoadedPromise]
B --> C{Policy?}
C -->|PERSISTENCE_UNTIL_NETWORK_SUCCESS and areFlagsReady| D[getVariantSync return]
C -->|NETWORK_FIRST or NETWORK_ONLY| E{fetchPromise set?}
E -->|Yes| F[await fetchPromise]
E -->|No| G[return NOT_READY fallback]
F -->|success| H[getVariantSync return]
F -->|error| I{areFlagsReady?}
I -->|Yes| H
I -->|No| J[return BACKEND_ERROR fallback]
subgraph fetchFlags
K[_fetchStartTime = now] --> L[build request]
L --> M[fetchPromise = myPromise]
M --> N{this.fetchPromise === myPromise?}
N -->|No - abandoned| O[discard result]
N -->|Yes| P[write flags + persist]
end
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[getVariant called] --> B[await persistenceLoadedPromise]
B --> C{Policy?}
C -->|PERSISTENCE_UNTIL_NETWORK_SUCCESS and areFlagsReady| D[getVariantSync return]
C -->|NETWORK_FIRST or NETWORK_ONLY| E{fetchPromise set?}
E -->|Yes| F[await fetchPromise]
E -->|No| G[return NOT_READY fallback]
F -->|success| H[getVariantSync return]
F -->|error| I{areFlagsReady?}
I -->|Yes| H
I -->|No| J[return BACKEND_ERROR fallback]
subgraph fetchFlags
K[_fetchStartTime = now] --> L[build request]
L --> M[fetchPromise = myPromise]
M --> N{this.fetchPromise === myPromise?}
N -->|No - abandoned| O[discard result]
N -->|Yes| P[write flags + persist]
end
Reviews (8): Last reviewed commit: "Address pr comment" | Re-trigger Greptile
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.
Introduces several changes to attain parity with other client feature flags SDKs