From c3d5da46f78de5a4ab7ea906e38ffa898cb55c29 Mon Sep 17 00:00:00 2001 From: hailin Date: Thu, 1 Jan 2026 08:08:18 -0800 Subject: [PATCH] fix(android): add polling fallback for session_started race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When multiple Android devices join a keygen session nearly simultaneously, the last joiner may miss the session_started gRPC event because it's sent before the device has fully set up its event subscription. This fix adds a 2-second delayed polling check after join to detect if the session has already started. If the session is in_progress and we haven't started keygen yet, trigger it via polling instead of relying solely on the session_started event. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../presentation/viewmodel/MainViewModel.kt | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/viewmodel/MainViewModel.kt b/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/viewmodel/MainViewModel.kt index 0924ee63..d2838a25 100644 --- a/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/viewmodel/MainViewModel.kt +++ b/backend/mpc-system/services/service-party-android/app/src/main/java/com/durian/tssparty/presentation/viewmodel/MainViewModel.kt @@ -502,8 +502,25 @@ class MainViewModel @Inject constructor( if (joinResult.sessionStatus == "in_progress") { android.util.Log.d("MainViewModel", "Session already in_progress, triggering keygen immediately") startKeygenAsJoiner() + } else { + // Otherwise, wait for session_started event + // But also poll session status after a delay in case we missed the event + // This handles the race condition where session_started is sent before we're ready + viewModelScope.launch { + delay(2000) // Wait 2 seconds + val joinInfo = pendingJoinKeygenInfo + if (joinInfo != null && joinInfo.sessionId == sessionInfo.sessionId) { + android.util.Log.d("MainViewModel", "Checking session status after delay...") + val statusResult = repository.getSessionStatus(sessionInfo.sessionId) + statusResult.onSuccess { status -> + if (status.status == "in_progress" && pendingJoinKeygenInfo != null) { + android.util.Log.d("MainViewModel", "Session is now in_progress (detected via polling), triggering keygen") + startKeygenAsJoiner() + } + } + } + } } - // Otherwise, wait for session_started event }, onFailure = { e -> android.util.Log.e("MainViewModel", "gRPC join failed", e)