Skip to content

Commit 166d858

Browse files
authored
fix(core): Prevent race condition on initial connection (#2432)
1 parent 5207134 commit 166d858

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed

packages/stream_chat_flutter_core/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## Upcoming
2+
3+
🐞 Fixed
4+
5+
- Fixed race condition where `connectUser` could be blocked when connectivity monitoring triggers
6+
during initial connection. [[#2409]](https://github.com/GetStream/stream-chat-flutter/issues/2409)
7+
18
## 9.19.0
29

310
- Updated `stream_chat` dependency to [`9.19.0`](https://pub.dev/packages/stream_chat/changelog).

packages/stream_chat_flutter_core/lib/src/stream_chat_core.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,13 @@ class StreamChatCoreState extends State<StreamChatCore>
237237
_unsubscribeFromConnectivityChange();
238238

239239
final stream = connectivityStream ?? Connectivity().onConnectivityChanged;
240-
_connectivitySubscription = stream.listen(
240+
241+
// Skip the first connectivity event which emits immediately on subscription
242+
// to avoid racing with initial connectUser call.
243+
// See: https://github.com/GetStream/stream-chat-flutter/issues/2409
244+
final skippedStream = stream.skip(1);
245+
246+
_connectivitySubscription = skippedStream.listen(
241247
_lifecycleManager.onConnectivityChanged,
242248
);
243249
}

packages/stream_chat_flutter_core/test/stream_chat_core_test.dart

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,5 +327,51 @@ void main() {
327327
verifyNever(mockClient.closeConnection);
328328
},
329329
);
330+
331+
testWidgets(
332+
'should skip initial connectivity event to avoid race with connectUser',
333+
(tester) async {
334+
// Create a connectivity stream that will emit immediately on subscription
335+
final testConnectivityController = BehaviorSubject.seeded(
336+
[ConnectivityResult.mobile],
337+
);
338+
339+
// Set up for reconnection scenario
340+
when(
341+
() => mockClient.wsConnectionStatus,
342+
).thenReturn(ConnectionStatus.disconnected);
343+
344+
// Clear any previous calls
345+
clearInteractions(mockClient);
346+
347+
// Arrange - pump widget with connectivity stream
348+
// The BehaviorSubject will emit [mobile] immediately on subscription
349+
// which should be skipped by skip(1)
350+
await tester.pumpWidget(
351+
MaterialApp(
352+
home: StreamChatCore(
353+
client: mockClient,
354+
connectivityStream: testConnectivityController.stream,
355+
child: const SizedBox(),
356+
),
357+
),
358+
);
359+
await tester.pumpAndSettle();
360+
361+
// Assert - the initial event from BehaviorSubject should be skipped
362+
verifyNever(mockClient.closeConnection);
363+
verifyNever(mockClient.openConnection);
364+
365+
// Now emit a connectivity change (this is the 2nd event, won't be skipped)
366+
testConnectivityController.add([ConnectivityResult.wifi]);
367+
await tester.pumpAndSettle();
368+
369+
// Assert - second event should trigger reconnection
370+
verify(mockClient.closeConnection).called(1);
371+
verify(mockClient.openConnection).called(1);
372+
373+
testConnectivityController.close();
374+
},
375+
);
330376
});
331377
}

0 commit comments

Comments
 (0)