SyncPlay cannot work across replicas #17

Open
opened 2026-09-13 13:33:16 +10:00 by unkin-agent · 0 comments
Member

Context: multi-replica stateless deployment (two 2-replica apps, cheeztv and fafflix, each one PostgreSQL plus valkey, no sticky sessions). Not a 12.0 regression — live in the deployed build. Tracking: #12.

Problem

Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs:49,55,61 holds _groups, _sessionToGroupMap and _activeUsers entirely in process, with zero persistence.

Members whose clients land on different pods cannot join the same group at all — from the second pod's view the group does not exist. SyncPlay is effectively non-functional in this deployment, and which users can watch together depends on load-balancer luck.

Proposal

A shared group registry (valkey, or the database if durability across a full restart matters) plus a cross-pod message bus so playback commands reach every member's owning pod.

Largest item in this set. Depends on #16 for the session → owning-pod routing.

Acceptance

  • Two independently constructed instances sharing one valkey and one real PostgreSQL: a group created through A is joinable through B, and play/pause/seek issued on A reaches the member session held by B.
  • Group state is cleaned up when its last member disconnects, and when the pod that created it dies.
  • Tests use PostgreSqlTestServer in tests/Jellyfin.Server.Tests and run in the postgres-migration-chain Woodpecker step (JELLYFIN_TEST_POSTGRES). In-memory providers have hidden different semantics and are how three bugs reached production.
Context: multi-replica stateless deployment (two 2-replica apps, `cheeztv` and `fafflix`, each one PostgreSQL plus valkey, no sticky sessions). Not a 12.0 regression — live in the deployed build. Tracking: #12. ## Problem `Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs:49,55,61` holds `_groups`, `_sessionToGroupMap` and `_activeUsers` entirely in process, with zero persistence. Members whose clients land on different pods cannot join the same group at all — from the second pod's view the group does not exist. SyncPlay is effectively non-functional in this deployment, and which users can watch together depends on load-balancer luck. ## Proposal A shared group registry (valkey, or the database if durability across a full restart matters) plus a cross-pod message bus so playback commands reach every member's owning pod. Largest item in this set. Depends on #16 for the session → owning-pod routing. ## Acceptance - Two independently constructed instances sharing one valkey and one real PostgreSQL: a group created through A is joinable through B, and play/pause/seek issued on A reaches the member session held by B. - Group state is cleaned up when its last member disconnects, and when the pod that created it dies. - Tests use `PostgreSqlTestServer` in `tests/Jellyfin.Server.Tests` and run in the `postgres-migration-chain` Woodpecker step (`JELLYFIN_TEST_POSTGRES`). In-memory providers have hidden different semantics and are how three bugs reached production.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unkin/jellyfin-ha-src#17