propagate shared-config and library-option changes between instances
Add a Redis pub/sub invalidation bus, publish from the configuration and library-option write paths, and drop the matching local cache entry on the instances that did not write. No-op without a Redis connection string, and fails open when it is unreachable.
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
namespace MediaBrowser.Common.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// A notice that one instance has written shared configuration, so every other instance has to drop
|
||||
/// its locally cached copy and read the shared file again.
|
||||
/// </summary>
|
||||
public sealed class ConfigurationInvalidation
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the cache this notice refers to.
|
||||
/// </summary>
|
||||
public ConfigurationInvalidationScope Scope { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets what was invalidated within the scope: the configuration key for
|
||||
/// <see cref="ConfigurationInvalidationScope.NamedConfiguration"/>, the library path for
|
||||
/// <see cref="ConfigurationInvalidationScope.LibraryOptions"/>, and <c>null</c> otherwise.
|
||||
/// </summary>
|
||||
public string? Target { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the identity of the instance that published the notice, so it can ignore its own.
|
||||
/// </summary>
|
||||
public string? OriginId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace MediaBrowser.Common.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Identifies which locally cached copy of the shared configuration a
|
||||
/// <see cref="ConfigurationInvalidation"/> refers to.
|
||||
/// </summary>
|
||||
public enum ConfigurationInvalidationScope
|
||||
{
|
||||
/// <summary>
|
||||
/// The system configuration cached by the configuration manager.
|
||||
/// </summary>
|
||||
SystemConfiguration = 0,
|
||||
|
||||
/// <summary>
|
||||
/// A single named configuration, identified by its key.
|
||||
/// </summary>
|
||||
NamedConfiguration = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The library options of a single collection folder, identified by its path.
|
||||
/// </summary>
|
||||
LibraryOptions = 2,
|
||||
|
||||
/// <summary>
|
||||
/// The library options of every collection folder, for changes to the library structure itself.
|
||||
/// </summary>
|
||||
AllLibraryOptions = 3
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Common.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Carries cache-invalidation notices between the instances that share one configuration directory.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The shared directory carries the content; this bus only carries the fact that it changed. Every
|
||||
/// implementation is expected to fail open: a bus that cannot deliver must not throw into the write
|
||||
/// path, leaving each instance on its own locally cached copy until it restarts.
|
||||
/// </remarks>
|
||||
public interface IConfigurationInvalidationBus
|
||||
{
|
||||
/// <summary>
|
||||
/// Announces that this instance has written shared configuration.
|
||||
/// </summary>
|
||||
/// <param name="scope">The cache that was written.</param>
|
||||
/// <param name="target">The configuration key or library path that was written, if any.</param>
|
||||
void Publish(ConfigurationInvalidationScope scope, string? target);
|
||||
|
||||
/// <summary>
|
||||
/// Registers the handler invoked for notices published by other instances.
|
||||
/// </summary>
|
||||
/// <param name="handler">The handler applying the invalidation locally.</param>
|
||||
void Subscribe(Action<ConfigurationInvalidation> handler);
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,13 @@ namespace MediaBrowser.Common.Configuration
|
||||
/// </summary>
|
||||
/// <param name="factories">The factories.</param>
|
||||
void AddParts(IEnumerable<IConfigurationFactory> factories);
|
||||
|
||||
/// <summary>
|
||||
/// Drops the locally cached copy of configuration another instance has written to the shared
|
||||
/// configuration directory, so the next read reloads it, and raises the local update event.
|
||||
/// </summary>
|
||||
/// <param name="key">The named configuration key, or <c>null</c> for the system configuration.</param>
|
||||
void InvalidateCachedConfiguration(string? key);
|
||||
}
|
||||
|
||||
public static class ConfigurationManagerExtensions
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Common.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// A no-op <see cref="IConfigurationInvalidationBus"/> used by single-instance installs and whenever
|
||||
/// the shared bus is unavailable. Every instance keeps its own cached configuration, which is the
|
||||
/// behaviour of an install that has only one.
|
||||
/// </summary>
|
||||
public sealed class NullConfigurationInvalidationBus : IConfigurationInvalidationBus
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the shared instance.
|
||||
/// </summary>
|
||||
public static NullConfigurationInvalidationBus Instance { get; } = new NullConfigurationInvalidationBus();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Publish(ConfigurationInvalidationScope scope, string? target)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Subscribe(Action<ConfigurationInvalidation> handler)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user