From bf777e65132e393aa286bccf0463d6fd8c6d31be Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Sun, 5 Jul 2026 16:08:10 +0530 Subject: [PATCH] Make IsConnectionCanceled available at LocalParticipant interface. (#4643) Can be used to keep track of pariticpants failing connection in a room by checking this when room closes the participant. --- pkg/rtc/participant.go | 14 ++-- pkg/rtc/types/interfaces.go | 1 + .../typesfakes/fake_local_participant.go | 72 +++++++++++++++++++ 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index 915a7022e..780deea9c 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -1427,19 +1427,23 @@ func (p *ParticipantImpl) IsReconnect() bool { } func (p *ParticipantImpl) maybeRecordRTCanceled(closeReason types.ParticipantCloseReason) { - if p.State() >= livekit.ParticipantInfo_ACTIVE { + if p.HasConnected() { return } - if closeReason == types.ParticipantCloseReasonClientRequestLeave || + if p.IsConnectionCanceled(closeReason) { + prometheus.IncrementParticipantRtcCanceled(1) + } +} + +func (p *ParticipantImpl) IsConnectionCanceled(closeReason types.ParticipantCloseReason) bool { + return closeReason == types.ParticipantCloseReasonClientRequestLeave || closeReason == types.ParticipantCloseReasonDuplicateIdentity || closeReason == types.ParticipantCloseReasonRoomClosed || closeReason == types.ParticipantCloseReasonMigrationRequested || closeReason == types.ParticipantCloseReasonMigrationComplete || // client closing signal connection too quickly, there is a time check to handle clients timing out and leaving without sending a leave message - (time.Since(p.params.SessionStartTime) < 3*time.Second && closeReason == types.ParticipantCloseReasonSignalSourceClose) { - prometheus.IncrementParticipantRtcCanceled(1) - } + (time.Since(p.params.SessionStartTime) < 3*time.Second && closeReason == types.ParticipantCloseReasonSignalSourceClose) } func (p *ParticipantImpl) Close(sendLeave bool, reason types.ParticipantCloseReason, isExpectedToResume bool) error { diff --git a/pkg/rtc/types/interfaces.go b/pkg/rtc/types/interfaces.go index 5d0c702ed..c47802ce5 100644 --- a/pkg/rtc/types/interfaces.go +++ b/pkg/rtc/types/interfaces.go @@ -414,6 +414,7 @@ type LocalParticipant interface { IsReady() bool ActiveAt() time.Time Disconnected() <-chan struct{} + IsConnectionCanceled(closeReason ParticipantCloseReason) bool IsIdle() bool SubscriberAsPrimary() bool GetClientInfo() *livekit.ClientInfo diff --git a/pkg/rtc/types/typesfakes/fake_local_participant.go b/pkg/rtc/types/typesfakes/fake_local_participant.go index d4198c2de..b7461f9ff 100644 --- a/pkg/rtc/types/typesfakes/fake_local_participant.go +++ b/pkg/rtc/types/typesfakes/fake_local_participant.go @@ -841,6 +841,17 @@ type FakeLocalParticipant struct { isClosedReturnsOnCall map[int]struct { result1 bool } + IsConnectionCanceledStub func(types.ParticipantCloseReason) bool + isConnectionCanceledMutex sync.RWMutex + isConnectionCanceledArgsForCall []struct { + arg1 types.ParticipantCloseReason + } + isConnectionCanceledReturns struct { + result1 bool + } + isConnectionCanceledReturnsOnCall map[int]struct { + result1 bool + } IsDependentStub func() bool isDependentMutex sync.RWMutex isDependentArgsForCall []struct { @@ -5946,6 +5957,67 @@ func (fake *FakeLocalParticipant) IsClosedReturnsOnCall(i int, result1 bool) { }{result1} } +func (fake *FakeLocalParticipant) IsConnectionCanceled(arg1 types.ParticipantCloseReason) bool { + fake.isConnectionCanceledMutex.Lock() + ret, specificReturn := fake.isConnectionCanceledReturnsOnCall[len(fake.isConnectionCanceledArgsForCall)] + fake.isConnectionCanceledArgsForCall = append(fake.isConnectionCanceledArgsForCall, struct { + arg1 types.ParticipantCloseReason + }{arg1}) + stub := fake.IsConnectionCanceledStub + fakeReturns := fake.isConnectionCanceledReturns + fake.recordInvocation("IsConnectionCanceled", []interface{}{arg1}) + fake.isConnectionCanceledMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeLocalParticipant) IsConnectionCanceledCallCount() int { + fake.isConnectionCanceledMutex.RLock() + defer fake.isConnectionCanceledMutex.RUnlock() + return len(fake.isConnectionCanceledArgsForCall) +} + +func (fake *FakeLocalParticipant) IsConnectionCanceledCalls(stub func(types.ParticipantCloseReason) bool) { + fake.isConnectionCanceledMutex.Lock() + defer fake.isConnectionCanceledMutex.Unlock() + fake.IsConnectionCanceledStub = stub +} + +func (fake *FakeLocalParticipant) IsConnectionCanceledArgsForCall(i int) types.ParticipantCloseReason { + fake.isConnectionCanceledMutex.RLock() + defer fake.isConnectionCanceledMutex.RUnlock() + argsForCall := fake.isConnectionCanceledArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeLocalParticipant) IsConnectionCanceledReturns(result1 bool) { + fake.isConnectionCanceledMutex.Lock() + defer fake.isConnectionCanceledMutex.Unlock() + fake.IsConnectionCanceledStub = nil + fake.isConnectionCanceledReturns = struct { + result1 bool + }{result1} +} + +func (fake *FakeLocalParticipant) IsConnectionCanceledReturnsOnCall(i int, result1 bool) { + fake.isConnectionCanceledMutex.Lock() + defer fake.isConnectionCanceledMutex.Unlock() + fake.IsConnectionCanceledStub = nil + if fake.isConnectionCanceledReturnsOnCall == nil { + fake.isConnectionCanceledReturnsOnCall = make(map[int]struct { + result1 bool + }) + } + fake.isConnectionCanceledReturnsOnCall[i] = struct { + result1 bool + }{result1} +} + func (fake *FakeLocalParticipant) IsDependent() bool { fake.isDependentMutex.Lock() ret, specificReturn := fake.isDependentReturnsOnCall[len(fake.isDependentArgsForCall)]