Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions contributingGuides/NETWORK_STATE_DETECTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,17 @@ const offline = !hasRadio || internetUnreachable || sustainedFailuresActive || s

`Reconnect.ts` registers an `AppStateMonitor.addBecameActiveListener` callback:
- If in hard stop → calls `NetworkState.refresh()` which triggers `NetInfo.refresh()` (bypasses stale `isInternetReachable` cache, see NetInfo issue #326)
- Always → calls `reconnect()` to catch up on missed Pusher events
- Always → flushes `SequentialQueue` so pending writes go out

It does not sync app data. A foreground proves nothing about missed events: if the socket died while backgrounded it resubscribes on foreground, and that resubscription syncs. If it survived, nothing was missed, and a hole in the update IDs is caught by gap detection.

## Recovery & Reconnect

**File:** `src/libs/actions/Reconnect.ts`

Subscribes to `NetworkState.onReachabilityConfirmed()` and `AppStateMonitor.addBecameActiveListener()`. Handles data synchronization:
Subscribes to `NetworkState.onReachabilityConfirmed()`, and is called by the Pusher private-user-channel resubscription (`PusherUtils.ts`) and the `Reauthentication` middleware. Handles data synchronization:

- Skips reconnection if no active session (`currentAccountID` is undefined)
- If `isLoadingApp` is true → calls `App.openApp()` (full initial load)
- Otherwise → calls `App.reconnectApp(lastUpdateIDAppliedToClient)` (incremental sync)
- Flushes `SequentialQueue` to send any pending write requests

Expand Down Expand Up @@ -203,7 +204,7 @@ Two debug options are available via the TestToolMenu (accessible in dev builds):
| `src/libs/NetworkState.ts` | Central hard stop state machine, NetInfo configuration/subscription, OS radio detection, and reachability tracking |
| `src/libs/FailureTracker.ts` | Counts failures, triggers sustained failure hard stop via listener pattern |
| `src/libs/Middleware/FailureTracking.ts` | Middleware that observes request outcomes and feeds FailureTracker |
| `src/libs/actions/Reconnect.ts` | Subscribes to reachability + foreground events, syncs app data after recovery |
| `src/libs/actions/Reconnect.ts` | Syncs app data after a reachability recovery; flushes the queue on foreground and on offline→online |
| `src/libs/Network/SequentialQueue.ts` | Write request queue, reads `getIsOffline()` synchronously for guard checks |
| `src/libs/actions/Network.ts` | Onyx actions for debug flags (forceOffline, simulatePoorConnection) |
| `src/hooks/useNetwork.ts` | Hook for components — uses `useSyncExternalStore` with `NetworkState.subscribe()` |
Expand Down
7 changes: 0 additions & 7 deletions src/libs/actions/Reconnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,6 @@ Onyx.connectWithoutView({
},
});

/**
* Centralized reconnection logic.
* Syncs app data with the server — fetches missed Onyx updates.
* Queue flushing is handled separately by the offline→online subscriber below.
*/
function reconnect() {
if (!currentAccountID) {
Log.info('[Reconnect] Skipping reconnection — no active session');
Expand Down Expand Up @@ -61,13 +56,11 @@ const initReconnect = () => {
wasOffline = offline;
});

// App came to foreground — sync data and flush queue
AppStateMonitor.addBecameActiveListener(() => {
Log.info('[Reconnect] App became active');
if (getIsOffline()) {
refreshNetworkState();
}
reconnect();
flush();
Comment thread
adhorodyski marked this conversation as resolved.
});
};
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/ReconnectTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ describe('Reconnect', () => {
expect(jest.mocked(reconnectApp)).toHaveBeenCalledTimes(1);
});

test('foreground triggers reconnect and flush when app becomes active while online', async () => {
test('foreground flushes the queue without syncing', async () => {
await Onyx.merge(ONYXKEYS.SESSION, {accountID: 1234, email: 'test@test.com'});
await Onyx.merge(ONYXKEYS.IS_LOADING_APP, false);
await waitForBatchedUpdates();
Expand All @@ -125,7 +125,7 @@ describe('Reconnect', () => {

becameActiveCallback();

expect(jest.mocked(reconnectApp)).toHaveBeenCalledTimes(1);
expect(jest.mocked(reconnectApp)).not.toHaveBeenCalled();
expect(jest.mocked(flush)).toHaveBeenCalledTimes(1);
});

Expand Down
Loading