0ffd4bdbea
Comment/XML-doc changes only, no code logic: - strip project-tracking references (WP*, P*-*, row-NN, #NN, Task N) from comments, keeping the explanatory rationale - add missing summaries, <param>, <returns>, <typeparam> and <inheritdoc/> - replace misused <inheritdoc/> with real docs; where <inheritdoc/> was combined with useful remarks, move the rationale into // comments - drop stale replicationActor <param> on DeploymentManagerActor ctor Remaining 5 are false positives (CWE-1236 x2, failures-1, year-0001, M365). Build 0 errors / 0 warnings.
100 lines
4.1 KiB
C#
100 lines
4.1 KiB
C#
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Scripting;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Scripting;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.InboundAPI;
|
|
|
|
/// <summary>
|
|
/// N1 (arch-review 06 round 2): the Inbound API consumer of the script-artifact
|
|
/// invalidation contract (docs/plans/2026-07-08-script-artifact-invalidation-contract.md,
|
|
/// handoff item (a)). Subscribes to <see cref="IScriptArtifactChangeBus"/> on host
|
|
/// start and, for every <c>ApiMethod</c> notification (e.g. a Transport bundle
|
|
/// import overwriting method scripts, published post-commit), drops the compiled
|
|
/// handler AND the known-bad record via
|
|
/// <see cref="InboundScriptExecutor.InvalidateMethod"/>, so the next request
|
|
/// recompiles from the fresh row without waiting for the per-request
|
|
/// revision-check self-heal.
|
|
/// <para>
|
|
/// Fast-path only: the revision check in <c>ExecuteAsync</c> remains the
|
|
/// correctness fallback — this bus is in-process/per-node and at-least-once
|
|
/// (contract §4), so a missed or duplicate notification must always be harmless.
|
|
/// The bus is optional (site roles and plain test hosts register none) — the
|
|
/// subscriber then no-ops. SharedScript/Template notifications are ignored: this
|
|
/// executor caches only ApiMethod handlers.
|
|
/// </para>
|
|
/// </summary>
|
|
public sealed class ScriptArtifactChangeSubscriber : IHostedService
|
|
{
|
|
private readonly InboundScriptExecutor _executor;
|
|
private readonly ApiMethodCache _methodCache;
|
|
private readonly ILogger<ScriptArtifactChangeSubscriber> _logger;
|
|
private readonly IScriptArtifactChangeBus? _bus;
|
|
private IDisposable? _subscription;
|
|
|
|
/// <summary>Initializes the subscriber.</summary>
|
|
/// <param name="executor">The compiled-handler cache to invalidate.</param>
|
|
/// <param name="methodCache">
|
|
/// The short-TTL resolved-<c>ApiMethod</c>-row cache to invalidate alongside
|
|
/// the compiled handler.
|
|
/// </param>
|
|
/// <param name="logger">Logger instance.</param>
|
|
/// <param name="bus">The change bus, or null when the host registers none (site roles, tests).</param>
|
|
public ScriptArtifactChangeSubscriber(
|
|
InboundScriptExecutor executor,
|
|
ApiMethodCache methodCache,
|
|
ILogger<ScriptArtifactChangeSubscriber> logger,
|
|
IScriptArtifactChangeBus? bus = null)
|
|
{
|
|
_executor = executor;
|
|
_methodCache = methodCache;
|
|
_logger = logger;
|
|
_bus = bus;
|
|
}
|
|
|
|
/// <summary>Subscribes to the change bus, when one is registered, to invalidate cached handlers.</summary>
|
|
/// <param name="cancellationToken">Cancellation token (unused).</param>
|
|
/// <returns>A completed task.</returns>
|
|
public Task StartAsync(CancellationToken cancellationToken)
|
|
{
|
|
if (_bus is null)
|
|
{
|
|
_logger.LogDebug(
|
|
"No IScriptArtifactChangeBus registered; inbound handler-cache freshness relies on the per-request revision check alone.");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
_subscription = _bus.Subscribe(OnChanged);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>Disposes the change-bus subscription.</summary>
|
|
/// <param name="cancellationToken">Cancellation token (unused).</param>
|
|
/// <returns>A completed task.</returns>
|
|
public Task StopAsync(CancellationToken cancellationToken)
|
|
{
|
|
_subscription?.Dispose();
|
|
_subscription = null;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private void OnChanged(ScriptArtifactsChanged notification)
|
|
{
|
|
if (!string.Equals(
|
|
notification.ArtifactKind, ScriptArtifactKinds.ApiMethod, StringComparison.Ordinal))
|
|
{
|
|
return; // only ApiMethod handlers are cached by this executor
|
|
}
|
|
|
|
foreach (var name in notification.Names)
|
|
{
|
|
_executor.InvalidateMethod(name);
|
|
_methodCache.Invalidate(name);
|
|
}
|
|
|
|
_logger.LogInformation(
|
|
"Invalidated {Count} inbound API method handler(s) after a {Source} script-artifact change.",
|
|
notification.Names.Count, notification.Source);
|
|
}
|
|
}
|