keep an applied invalidation from inducing a write that publishes back
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
namespace MediaBrowser.Common.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Extensions for <see cref="IConfigurationInvalidationBus"/>.
|
||||
/// </summary>
|
||||
public static class ConfigurationInvalidationBusExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Announces a write this instance originated, and stays silent for a write induced by an
|
||||
/// invalidation another instance published.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the backstop for the write path: a consumer reacting to an applied invalidation by
|
||||
/// writing - including a plugin that knows nothing about the bus - cannot turn that write into a
|
||||
/// notice of its own.
|
||||
/// </remarks>
|
||||
/// <param name="bus">The bus.</param>
|
||||
/// <param name="scope">The cache that was written.</param>
|
||||
/// <param name="target">The configuration key or library path that was written, if any.</param>
|
||||
public static void PublishLocalWrite(this IConfigurationInvalidationBus bus, ConfigurationInvalidationScope scope, string? target)
|
||||
{
|
||||
if (ConfigurationInvalidationContext.IsApplyingRemoteInvalidation)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bus.Publish(scope, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Common.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Marks the flow of control that is applying an invalidation published by another instance, so the
|
||||
/// reactions to it can tell a remote write apart from a local one.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Applying an invalidation raises the same update events a local save raises, because the in-process
|
||||
/// consumers have to re-read the configuration either way. Some of those consumers answer an update by
|
||||
/// writing, and that write must neither repeat what the publishing instance already did nor fan back
|
||||
/// out over the bus. The flag rides the execution context, so it reaches the queued and asynchronous
|
||||
/// event handlers as well as the synchronous ones.
|
||||
/// </remarks>
|
||||
public static class ConfigurationInvalidationContext
|
||||
{
|
||||
private static readonly AsyncLocal<bool> _applyingRemoteInvalidation = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the current flow of control is applying an invalidation
|
||||
/// published by another instance rather than handling a local save.
|
||||
/// </summary>
|
||||
public static bool IsApplyingRemoteInvalidation => _applyingRemoteInvalidation.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Marks the current flow of control as applying a remote invalidation until the returned scope is
|
||||
/// disposed.
|
||||
/// </summary>
|
||||
/// <returns>The scope to dispose once the invalidation has been applied.</returns>
|
||||
public static IDisposable BeginApply() => new ApplyScope();
|
||||
|
||||
private sealed class ApplyScope : IDisposable
|
||||
{
|
||||
private readonly bool _previous;
|
||||
private bool _disposed;
|
||||
|
||||
public ApplyScope()
|
||||
{
|
||||
_previous = _applyingRemoteInvalidation.Value;
|
||||
_applyingRemoteInvalidation.Value = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
_applyingRemoteInvalidation.Value = _previous;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user