fix(android): add logging for session event subscription debugging

- Add warning log when parties miss session event broadcast (message-router)
- Add logging for subscribeSessionEvents to detect null asyncStub
- Add sessionStatusPollingJob field for future fallback polling mechanism

This helps diagnose why Android parties are not receiving session_started events.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-01-01 09:23:38 -08:00
parent eb3f71fa2e
commit e2451874ea
3 changed files with 35 additions and 1 deletions

View File

@ -4,6 +4,8 @@ import (
"sync"
pb "github.com/rwadurian/mpc-system/api/grpc/router/v1"
"github.com/rwadurian/mpc-system/pkg/logger"
"go.uber.org/zap"
)
// SessionEventBroadcaster manages session event subscriptions and broadcasting
@ -69,16 +71,34 @@ func (b *SessionEventBroadcaster) BroadcastToParties(event *pb.SessionEvent, par
b.mu.RLock()
defer b.mu.RUnlock()
sentCount := 0
missedParties := []string{}
for _, partyID := range partyIDs {
if ch, exists := b.subscribers[partyID]; exists {
// Non-blocking send
select {
case ch <- event:
sentCount++
default:
// Channel full, skip this subscriber
missedParties = append(missedParties, partyID+" (channel full)")
}
} else {
// Party not subscribed - this is a problem for session_started events!
missedParties = append(missedParties, partyID+" (not subscribed)")
}
}
// Log if any parties were missed (helps debug event delivery issues)
if len(missedParties) > 0 {
logger.Warn("Some parties missed session event broadcast",
zap.String("event_type", event.EventType),
zap.String("session_id", event.SessionId),
zap.Int("sent_count", sentCount),
zap.Int("missed_count", len(missedParties)),
zap.Strings("missed_parties", missedParties))
}
}
// SubscriberCount returns the number of active subscribers

View File

@ -854,9 +854,19 @@ class GrpcClient @Inject constructor() {
}
}
asyncStub?.subscribeSessionEvents(request, observer)
val currentAsyncStub = asyncStub
if (currentAsyncStub == null) {
Log.e(TAG, "subscribeSessionEvents: asyncStub is null! Cannot subscribe.")
close(Exception("gRPC not connected - asyncStub is null"))
return@callbackFlow
}
Log.d(TAG, "subscribeSessionEvents: Starting subscription for partyId=$partyId")
currentAsyncStub.subscribeSessionEvents(request, observer)
Log.d(TAG, "subscribeSessionEvents: Subscription request sent")
awaitClose {
Log.d(TAG, "subscribeSessionEvents: Flow closed for partyId=$partyId")
eventStreamSubscribed.set(false)
eventStreamPartyId = null
}

View File

@ -50,6 +50,10 @@ class TssRepository @Inject constructor(
// This allows session_started events to be matched even if _currentSession is not yet set
private var pendingSessionId: String? = null
// Fallback polling job for session status (handles gRPC stream disconnection on Android)
// Android gRPC streams can disconnect when app goes to background, so we poll as backup
private var sessionStatusPollingJob: Job? = null
/**
* Get the current party ID
*/