HA: in-process single-instance assumptions under multi-replica deployment (tracking) #12

Open
opened 2026-09-13 13:33:15 +10:00 by unkin-agent · 1 comment
Member

Problem

This fork runs Jellyfin as multiple stateless pods in Kubernetes: two 2-replica deployments, cheeztv and fafflix, each sharing one PostgreSQL plus a valkey. Sticky sessions are deliberately not used — the deployment is stateless as much as possible.

Several subsystems still hold in-process state that assumes a single instance. Effects range from silent user-visible data loss to duplicated background work and stale UI. None of these are regressions from the Jellyfin 12.0 upgrade — all are live in the currently deployed build.

Proposal

Work the issues below in this order. Some share a fix or a prerequisite; those links are repeated on the issues themselves.

  1. #13 — UserDataManager cache causes lost updates across replicas. Silent data loss, in production now.
  2. #14 — Scheduled tasks missing from GatedTaskKeys run on every replica. Cheap, large win.
  3. #15 — Shared-config and library-visibility changes do not propagate between replicas.
  4. #16 — No shared session directory; cross-pod session operations fail. Prerequisite for #17 and #20.
  5. #17 — SyncPlay cannot work across replicas. Largest item; depends on #16.
  6. #18 — QuickConnect fails intermittently across replicas. Self-contained.
  7. #19 — LibraryManager item cache serves stale metadata across replicas. Likely one piece of work with #13.
  8. #20 — Live WebSocket notifications only reach clients on the writing pod. Falls out of #16.
  9. #21 — Transcode takeover is never invoked.
  10. #22 — Device capabilities are not persisted. Needs an append-only migration.
  11. #23 — Jellyfin.Database.Tests.PostgreSQL is not run in CI and has 3 failing tests.
  12. #24 — DeviceId writes device.txt non-atomically on a shared volume.
  13. #25 — On-demand metadata refresh can duplicate the leader's work. Lowest priority.

Related, in the build repo: unkin/jellyfin-ha#11 documents the HA env-var contract.

Every multi-replica fix here is verified against real PostgreSQL with two independently constructed instances, using PostgreSqlTestServer in tests/Jellyfin.Server.Tests and the postgres-migration-chain Woodpecker step (JELLYFIN_TEST_POSTGRES). In-memory providers have hidden different semantics and are how three bugs reached production.

Acceptance

Every linked issue is closed, or explicitly deferred with a recorded reason.

## Problem This fork runs Jellyfin as multiple stateless pods in Kubernetes: two 2-replica deployments, `cheeztv` and `fafflix`, each sharing one PostgreSQL plus a valkey. Sticky sessions are deliberately not used — the deployment is stateless as much as possible. Several subsystems still hold in-process state that assumes a single instance. Effects range from silent user-visible data loss to duplicated background work and stale UI. None of these are regressions from the Jellyfin 12.0 upgrade — all are live in the currently deployed build. ## Proposal Work the issues below in this order. Some share a fix or a prerequisite; those links are repeated on the issues themselves. 1. #13 — `UserDataManager` cache causes lost updates across replicas. Silent data loss, in production now. 2. #14 — Scheduled tasks missing from `GatedTaskKeys` run on every replica. Cheap, large win. 3. #15 — Shared-config and library-visibility changes do not propagate between replicas. 4. #16 — No shared session directory; cross-pod session operations fail. Prerequisite for #17 and #20. 5. #17 — SyncPlay cannot work across replicas. Largest item; depends on #16. 6. #18 — QuickConnect fails intermittently across replicas. Self-contained. 7. #19 — `LibraryManager` item cache serves stale metadata across replicas. Likely one piece of work with #13. 8. #20 — Live WebSocket notifications only reach clients on the writing pod. Falls out of #16. 9. #21 — Transcode takeover is never invoked. 10. #22 — Device capabilities are not persisted. Needs an append-only migration. 11. #23 — `Jellyfin.Database.Tests.PostgreSQL` is not run in CI and has 3 failing tests. 12. #24 — `DeviceId` writes `device.txt` non-atomically on a shared volume. 13. #25 — On-demand metadata refresh can duplicate the leader's work. Lowest priority. Related, in the build repo: unkin/jellyfin-ha#11 documents the HA env-var contract. Every multi-replica fix here is verified against real PostgreSQL with two independently constructed instances, using `PostgreSqlTestServer` in `tests/Jellyfin.Server.Tests` and the `postgres-migration-chain` Woodpecker step (`JELLYFIN_TEST_POSTGRES`). In-memory providers have hidden different semantics and are how three bugs reached production. ## Acceptance Every linked issue is closed, or explicitly deferred with a recorded reason.
Author
Member

Same class, different location: #27 covers the SSO plugin holding OAuth state in-process (third-party plugin, not Jellyfin itself), so it is tracked separately rather than as a child of this issue.

Same class, different location: #27 covers the SSO plugin holding OAuth state in-process (third-party plugin, not Jellyfin itself), so it is tracked separately rather than as a child of this issue.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unkin/jellyfin-ha-src#12