Skip to content

Conversation

@aleksandar-apostolov
Copy link
Collaborator

Goal

Ensure the connection recovery evaluator reconnects in the intended lifecycle/network scenarios and add coverage for the lifecycle/recovery/subscribe helper packages that were previously untested.

Implementation

  • Implemented StreamConnectionRecoveryEvaluatorImpl to gate reconnection on prior connectivity, foreground lifecycle, and either a returning-to-foreground or newly available network signal while persisting the last usable snapshot for reconnect attempts.
  • Added a comprehensive test suite for the evaluator
  • Introduced tests for StreamLifecycleMonitor

Testing

Run the sample and go into background foreground. Check the logs to see if you are correctly disconnected then connected.

Checklist

# Conflicts:
#	app/src/main/java/io/getstream/android/core/sample/SampleActivity.kt
#	app/src/main/java/io/getstream/android/core/sample/client/StreamClient.kt
#	app/src/main/java/io/getstream/android/core/sample/ui/ConnectionStateCard.kt
#	app/src/main/java/io/getstream/android/core/sample/ui/NetworkInfoCard.kt
#	app/src/main/java/io/getstream/android/core/sample/ui/NetworkInfoComponents.kt
#	gradle/libs.versions.toml
#	stream-android-core/build.gradle.kts
#	stream-android-core/src/main/AndroidManifest.xml
#	stream-android-core/src/main/java/io/getstream/android/core/api/StreamClient.kt
#	stream-android-core/src/main/java/io/getstream/android/core/api/components/StreamAndroidComponentsProvider.kt
#	stream-android-core/src/main/java/io/getstream/android/core/api/model/connection/network/StreamNetworkInfo.kt
#	stream-android-core/src/main/java/io/getstream/android/core/api/model/connection/network/StreamNetworkState.kt
#	stream-android-core/src/main/java/io/getstream/android/core/api/observers/network/StreamNetworkMonitor.kt
#	stream-android-core/src/main/java/io/getstream/android/core/api/observers/network/StreamNetworkMonitorListener.kt
#	stream-android-core/src/main/java/io/getstream/android/core/api/socket/monitor/StreamHealthMonitor.kt
#	stream-android-core/src/main/java/io/getstream/android/core/api/utils/Algebra.kt
#	stream-android-core/src/main/java/io/getstream/android/core/internal/client/StreamClientImpl.kt
#	stream-android-core/src/main/java/io/getstream/android/core/internal/components/StreamAndroidComponentsProviderImpl.kt
#	stream-android-core/src/main/java/io/getstream/android/core/internal/observers/network/StreamNetworkMonitorCallback.kt
#	stream-android-core/src/main/java/io/getstream/android/core/internal/observers/network/StreamNetworkMonitorImpl.kt
#	stream-android-core/src/main/java/io/getstream/android/core/internal/observers/network/StreamNetworkMonitorUtils.kt
#	stream-android-core/src/main/java/io/getstream/android/core/internal/observers/network/StreamNetworkSignalProcessing.kt
#	stream-android-core/src/main/java/io/getstream/android/core/internal/observers/network/StreamNetworkSnapshotBuilder.kt
#	stream-android-core/src/test/java/io/getstream/android/core/api/StreamClientFactoryTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/api/components/StreamAndroidComponentsProviderLatestApiTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/api/components/StreamAndroidComponentsProviderLegacyApiTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/api/observers/network/StreamNetworkMonitorFactoryTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/api/observers/network/StreamNetworkMonitorListenerTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/api/utils/AlgebraTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/internal/client/StreamClientIImplTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkMonitorCallbackTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkMonitorImplTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkMonitorUtilsTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkSignalProcessingLatestApiTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkSignalProcessingLegacyApiTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkSignalProcessingTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkSnapshotBuilderLatestApiTest.kt
#	stream-android-core/src/test/java/io/getstream/android/core/internal/observers/network/StreamNetworkSnapshotBuilderLegacyApiTest.kt
@github-actions
Copy link
Contributor

github-actions bot commented Nov 21, 2025

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled.

🎉 Great job! This PR is ready for review.

@aleksandar-apostolov aleksandar-apostolov changed the title Add connection recovery handler Add connection recovery handler and lifecycle monitor Nov 21, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request implements connection recovery handling and lifecycle monitoring for the Stream Android core SDK. The changes introduce a sophisticated system that manages WebSocket reconnection based on network availability and app lifecycle state (foreground/background), ensuring the client only attempts to reconnect when appropriate conditions are met.

Key Changes

  • Connection Recovery Evaluator: Implements StreamConnectionRecoveryEvaluatorImpl that evaluates connection, lifecycle, and network states to determine when to reconnect or disconnect, persisting the last known network snapshot for reconnection attempts.
  • Lifecycle Monitoring: Adds StreamLifecycleMonitor to track app foreground/background transitions using AndroidX ProcessLifecycleOwner.
  • Coordinated State Management: Introduces StreamNetworkAndLifeCycleMonitor to bridge network and lifecycle signals, providing a unified view for connection recovery decisions.

Reviewed changes

Copilot reviewed 45 out of 45 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
StreamConnectionRecoveryEvaluatorImpl.kt Core logic for evaluating when to reconnect/disconnect based on state transitions
StreamLifecycleMonitorImpl.kt Monitors app lifecycle events and notifies registered listeners
StreamNetworkAndLifecycleMonitorImpl.kt Combines network and lifecycle monitoring into a single coordinator
StreamClientImpl.kt Refactored to use recovery evaluator and lifecycle monitoring; added token retry logic
ForEach.kt Helper extension for invoking suspending blocks over subscription listeners
Result.kt Added onTokenError extension for handling authentication token errors
Flows.kt Utility for updating MutableStateFlow values
StreamObservable.kt New interface extracting subscription pattern from StreamSubscriptionManager
Test files Comprehensive test coverage for recovery evaluator, lifecycle monitor, and integration scenarios
build.gradle.kts Added AndroidX lifecycle dependencies
AndroidManifest.xml Added ACCESS_WIFI_STATE permission

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Collaborator

@gpunto gpunto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing this in the sample:

  1. Launch it and then go in background
  2. In some cases, I get a socket failure in background due to java.net.SocketException: Software caused connection abort
  3. Then I get the corresponding state [notifyState] Notifying state: Disconnected(cause=java.net.SocketException: Software caused connection abort)
  4. And then, if I resume the app, it gets stuck, i.e. no more logging occurs and I get an ANR, so the main thread seems to be blocked

In other cases, the failure at step 2 doesn't occur and the socket is reconnected, i.e. I get Notifying state: Connected(..., but still the app is stuck.

forEachSuspend might be a candidate, but I'm not sure if it's that or something else.

aleksandar-apostolov and others added 5 commits November 26, 2025 11:32
…ternal/recovery/StreamConnectionRecoveryEvaluatorImpl.kt

Co-authored-by: Gianmarco <47775302+gpunto@users.noreply.github.com>
…i/utils/Result.kt

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…ternal/observers/StreamNetworkAndLifeCycleMonitor.kt

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 43 out of 43 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

aleksandar-apostolov and others added 3 commits November 26, 2025 12:10
…ternal/client/StreamClientImpl.kt

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…ternal/recovery/StreamConnectionRecoveryEvaluatorImpl.kt

Co-authored-by: Gianmarco <47775302+gpunto@users.noreply.github.com>
@sonarqubecloud
Copy link

@aleksandar-apostolov aleksandar-apostolov merged commit 96731c4 into develop Nov 26, 2025
6 checks passed
@aleksandar-apostolov aleksandar-apostolov deleted the connection-recovery-handler branch November 26, 2025 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:new-feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants