Skip to content

Commit 87e3821

Browse files
Update App state listener to improve synchronization
1 parent 98262f0 commit 87e3821

File tree

2 files changed

+17
-2
lines changed

2 files changed

+17
-2
lines changed

CHANGES.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
1.2.1 (July XX, 2025)
2+
- Updated the application state listener to synchronize feature flag definitions when the app returns to foreground after exceeding the SDK's features refresh rate.
3+
14
1.2.0 (June 25, 2025)
25
- Added support for rule-based segments. These segments determine membership at runtime by evaluating their configured rules against the user attributes provided to the SDK.
36
- Added support for feature flag prerequisites. This allows customers to define dependency conditions between flags, which are evaluated before any allowlists or targeting rules.

src/platform/RNSignalListener.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const EVENT_NAME = 'for AppState change events.';
2020
export class RNSignalListener implements ISignalListener {
2121
private _lastTransition: Transition | undefined;
2222
private _appStateSubscription: NativeEventSubscription | undefined;
23+
private _lastBgTimestamp: number | undefined;
2324

2425
constructor(private syncManager: ISyncManager, private settings: ISettings & { flushDataOnBackground?: boolean }) {}
2526

@@ -39,6 +40,10 @@ export class RNSignalListener implements ISignalListener {
3940
return transition;
4041
}
4142

43+
private _mustSyncAll() {
44+
return this.settings.sync.enabled && this._lastBgTimestamp && this._lastBgTimestamp < Date.now() - this.settings.scheduler.featuresRefreshRate;
45+
}
46+
4247
private _handleAppStateChange = (nextAppState: AppStateStatus) => {
4348
const action = this._getTransition(nextAppState);
4449

@@ -51,10 +56,17 @@ export class RNSignalListener implements ISignalListener {
5156
// In 2, PushManager is resumed in case it was paused and the SDK is running in push mode.
5257
// If running in polling mode, either pushManager is not defined (e.g., streamingEnabled is false)
5358
// or calling pushManager.start has no effect because it was disabled (PUSH_NONRETRYABLE_ERROR).
54-
if (this.syncManager.pushManager) this.syncManager.pushManager.start();
59+
if (this.syncManager.pushManager) {
60+
this.syncManager.pushManager.start();
61+
62+
// Sync all if singleSync is disabled and background time exceeds features refresh rate
63+
// For streaming, this compensates the re-connection delay, and for polling, it compensates the suspension of scheduled tasks during background.
64+
if (this._mustSyncAll()) this.syncManager.pollingManager!.syncAll();
65+
}
5566

5667
break;
5768
case TO_BACKGROUND:
69+
this._lastBgTimestamp = Date.now();
5870
this.settings.log.debug(
5971
`App transition to background${this.syncManager.pushManager ? '. Pausing streaming' : ''}${
6072
this.settings.flushDataOnBackground ? '. Flushing events and impressions' : ''
@@ -65,7 +77,7 @@ export class RNSignalListener implements ISignalListener {
6577
// Here, PushManager is paused in case the SDK is running in push mode, to close streaming connection for Android.
6678
// In iOS it is not strictly required, since connections are automatically closed/resumed by the OS.
6779
// The remaining SyncManager components (PollingManager and Submitter) don't need to be stopped, even if running in
68-
// polling mode, because sync tasks are "delayed" during background, since JS timers callbacks are executed only
80+
// polling mode, because sync tasks are suspended during background, since JS timers callbacks are executed only
6981
// when the app is in foreground (https://github.com/facebook/react-native/issues/12981#issuecomment-652745831).
7082
// Other features like Fetch, AsyncStorage, AppState and NetInfo listeners, can be used in background.
7183
if (this.syncManager.pushManager) this.syncManager.pushManager.stop();

0 commit comments

Comments
 (0)