b662ffa48f
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.
74 lines
2.2 KiB
C#
74 lines
2.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using MediaBrowser.Common.Configuration;
|
|
|
|
namespace Jellyfin.Server.Implementations.Tests.Configuration;
|
|
|
|
/// <summary>
|
|
/// An in-process stand-in for the Redis pub/sub bus: every endpoint connected to one fabric receives
|
|
/// what the others publish, and never its own notices.
|
|
/// </summary>
|
|
internal sealed class FakeInvalidationBusFabric
|
|
{
|
|
private readonly List<Endpoint> _endpoints = new();
|
|
|
|
/// <summary>
|
|
/// Connects a new instance to the fabric.
|
|
/// </summary>
|
|
/// <param name="originId">The identity of the connecting instance.</param>
|
|
/// <returns>The bus of that instance.</returns>
|
|
public IConfigurationInvalidationBus Connect(string originId)
|
|
{
|
|
var endpoint = new Endpoint(this, originId);
|
|
lock (_endpoints)
|
|
{
|
|
_endpoints.Add(endpoint);
|
|
}
|
|
|
|
return endpoint;
|
|
}
|
|
|
|
private void Broadcast(ConfigurationInvalidation invalidation)
|
|
{
|
|
Endpoint[] endpoints;
|
|
lock (_endpoints)
|
|
{
|
|
endpoints = _endpoints.ToArray();
|
|
}
|
|
|
|
foreach (var endpoint in endpoints.Where(e => !string.Equals(e.OriginId, invalidation.OriginId, StringComparison.Ordinal)))
|
|
{
|
|
endpoint.Deliver(invalidation);
|
|
}
|
|
}
|
|
|
|
private sealed class Endpoint : IConfigurationInvalidationBus
|
|
{
|
|
private readonly FakeInvalidationBusFabric _fabric;
|
|
private readonly List<Action<ConfigurationInvalidation>> _handlers = new();
|
|
|
|
public Endpoint(FakeInvalidationBusFabric fabric, string originId)
|
|
{
|
|
_fabric = fabric;
|
|
OriginId = originId;
|
|
}
|
|
|
|
public string OriginId { get; }
|
|
|
|
public void Publish(ConfigurationInvalidationScope scope, string? target)
|
|
=> _fabric.Broadcast(new ConfigurationInvalidation { Scope = scope, Target = target, OriginId = OriginId });
|
|
|
|
public void Subscribe(Action<ConfigurationInvalidation> handler)
|
|
=> _handlers.Add(handler);
|
|
|
|
public void Deliver(ConfigurationInvalidation invalidation)
|
|
{
|
|
foreach (var handler in _handlers)
|
|
{
|
|
handler(invalidation);
|
|
}
|
|
}
|
|
}
|
|
}
|