mirror of
https://github.com/livekit/livekit.git
synced 2026-09-09 22:45:47 +00:00
* telemetry: support roomID change for a participant A room can get a new id while participants are connected. Key stats workers as map[roomID]map[participantID] so moving a room is a single map splice, and add reKeyRoom/RoomIDChanged to do the move. Stats collected before the change are sealed off with the room they were collected in so they stay attributed to it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * telemetry: close superseded worker on re-key collision Only one worker can be keyed at (room, participant). If a re-key lands on a room that already has a worker for the same participant, keep the one already filed there and close the superseded one so it drains and is reaped instead of lingering in the flush list. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * telemetry: hand references to the successor on force close A ReferenceGuard records that it activated some worker, not which one, so a superseded worker cannot just drop its references - the survivor would be left with references it never sees released and would never close. Hand them over instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
64 lines
2.3 KiB
Go
64 lines
2.3 KiB
Go
package telemetry
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestStatsWorker(t *testing.T) {
|
|
t.Run("reference counted close works", func(t *testing.T) {
|
|
var g0, g1 ReferenceGuard
|
|
w := newStatsWorker(t.Context(), nil, "", "", "", "", &g0)
|
|
require.False(t, w.Closed(&g1))
|
|
require.False(t, w.Close(&g0))
|
|
require.False(t, w.Closed(&g1))
|
|
require.True(t, w.Close(&g1))
|
|
require.True(t, w.Closed(&g1))
|
|
})
|
|
|
|
// a ReferenceGuard records that it activated some worker, not which one, so a
|
|
// superseded worker has to hand its references to the one reachable in its place
|
|
t.Run("force close hands references to the successor", func(t *testing.T) {
|
|
t.Run("a guard shared by both workers", func(t *testing.T) {
|
|
// the second worker never got a reference, the guard was already activated
|
|
var g ReferenceGuard
|
|
superseded := newStatsWorker(t.Context(), nil, "", "", "", "", &g)
|
|
survivor := newStatsWorker(t.Context(), nil, "", "", "", "", &g)
|
|
require.Equal(t, 1, superseded.refCount.count)
|
|
require.Equal(t, 0, survivor.refCount.count)
|
|
|
|
require.True(t, superseded.ForceClose(survivor))
|
|
require.Equal(t, 0, superseded.refCount.count)
|
|
require.Equal(t, 1, survivor.refCount.count)
|
|
|
|
// without the hand over this would leave the survivor at -1 and never closed
|
|
require.True(t, survivor.Close(&g))
|
|
require.True(t, survivor.Closed(&g))
|
|
})
|
|
|
|
t.Run("a guard per worker", func(t *testing.T) {
|
|
var gSuperseded, gSurvivor ReferenceGuard
|
|
superseded := newStatsWorker(t.Context(), nil, "", "", "", "", &gSuperseded)
|
|
survivor := newStatsWorker(t.Context(), nil, "", "", "", "", &gSurvivor)
|
|
|
|
require.True(t, superseded.ForceClose(survivor))
|
|
require.Equal(t, 2, survivor.refCount.count)
|
|
|
|
// the superseded worker's owner departs, it must not close the survivor early
|
|
require.False(t, survivor.Close(&gSuperseded))
|
|
require.True(t, survivor.Close(&gSurvivor))
|
|
})
|
|
|
|
t.Run("closing an already closed worker holds on to its references", func(t *testing.T) {
|
|
var g ReferenceGuard
|
|
superseded := newStatsWorker(t.Context(), nil, "", "", "", "", &g)
|
|
survivor := newStatsWorker(t.Context(), nil, "", "", "", "", nil)
|
|
|
|
require.True(t, superseded.ForceClose(nil))
|
|
require.False(t, superseded.ForceClose(survivor))
|
|
require.Equal(t, 0, survivor.refCount.count)
|
|
})
|
|
})
|
|
}
|