fix(ha): propagate shared-config and library-visibility changes between replicas #29
Reference in New Issue
Block a user
Delete Branch "benvin/config-propagation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Every replica caches the system configuration, each named configuration and each library's options for the life of the process, with no invalidation path, so a change made on one pod is silently absent from the others. Disabling a library is the sharp edge: the stale pods keep serving it to every user until they restart.
Closes #15
Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs:383 — applying a remote NamedConfiguration invalidation replays the same
NamedConfigurationUpdatedevent a local admin save raises. RecordingsManager.OnNamedConfigurationUpdated (src/Jellyfin.LiveTv/Recordings/RecordingsManager.cs:445) reacts to the "livetv" key by callingCreateRecordingFolders(), which can callAddVirtualFolder→CollectionFolder.SaveLibraryOptions(Emby.Server.Implementations/Library/LibraryManager.cs:3782), which publishes a further invalidation → two replicas can independently create the same missing recording folder off one config change and re-publish about it. Give the subscriber a way to apply an invalidation without replaying the events write-path handlers use for their own side effects, or make CreateRecordingFolders/AddVirtualFolder race-safe against a concurrent peer reacting to the same change.if (HttpPort != 0 && HttpsPort != 0 && !IsApplyingRemoteInvalidation)block in the remote-apply guard also skips the port-mismatch check andNotifyPendingRestart()on replicas that did not originate the change. A replica receiving a remote network/port invalidation never compares its own boundHttpPort/HttpsPortagainst the refreshed config and never flagsHasPendingRestart, so it keeps running on the stale port indefinitely — reintroduces the staleness this PR exists to remove, for exactly the consumer named in scope. Scope the guard to only theIsPortAuthorized/SaveConfiguration()write, not the mismatch detection and restart notification.InvalidateCachedConfigurationis a new member on a public interface in a plugin-facing assembly with no default body; any third-partyIConfigurationManagerimplementer fails to compile against the new contract.No findings.