feat(commons/transport): ScriptArtifactsChanged invalidation contract + post-commit publish from bundle import (consumer lands in plan 06)
New Commons seam: ScriptArtifactsChanged record + ScriptArtifactKinds + the IScriptArtifactChangeBus pub/sub interface. Host ships InProcessScriptArtifactChangeBus (lock-free copy-on-write, swallow-and-log per subscriber) registered as a central-role singleton. BundleImporter gains an optional IScriptArtifactChangeBus? and, AFTER tx.CommitAsync, publishes one notification per script-bearing kind (ApiMethod/ SharedScript/Template) whose resolution was Overwrite/Rename, using post-resolution names — fully guarded so a bad subscriber can't fail a committed import. Contract + plan-06 handoff table documented. No consumer yet (additive; publisher is correct). Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Scripting;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Scripting;
|
||||
|
||||
/// <summary>
|
||||
/// In-process, per-node publish/subscribe seam for
|
||||
/// <see cref="ScriptArtifactsChanged"/>. Producers (e.g. the Transport bundle
|
||||
/// importer, the ManagementActor script-editing paths) publish AFTER their mutating
|
||||
/// transaction commits; consumers (e.g. the Inbound API compiled-handler cache)
|
||||
/// subscribe and evict.
|
||||
/// <para>
|
||||
/// A conforming implementation MUST swallow-and-log any exception thrown by a
|
||||
/// subscriber's handler — a misbehaving consumer must never fault a producer's
|
||||
/// commit path.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public interface IScriptArtifactChangeBus
|
||||
{
|
||||
/// <summary>Publishes a change notification to every current subscriber. Never throws on a subscriber fault.</summary>
|
||||
/// <param name="notification">The change notification to deliver.</param>
|
||||
void Publish(ScriptArtifactsChanged notification);
|
||||
|
||||
/// <summary>Subscribes a handler; dispose the returned token to unsubscribe.</summary>
|
||||
/// <param name="handler">The handler invoked for each published notification.</param>
|
||||
/// <returns>A disposable that removes the subscription when disposed.</returns>
|
||||
IDisposable Subscribe(Action<ScriptArtifactsChanged> handler);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Scripting;
|
||||
|
||||
/// <summary>
|
||||
/// Advisory notification that one or more script-bearing artifacts changed on this
|
||||
/// node. It is <b>at-least-once</b> and is published only <b>AFTER</b> the mutating
|
||||
/// transaction commits — never inside it (a notification for a rolled-back write is
|
||||
/// worse than a missed one).
|
||||
/// <para>
|
||||
/// Consumers MUST invalidate any compiled/cached artifact keyed by these names, and
|
||||
/// MUST ALSO be able to self-heal <i>without</i> the notification (e.g. a
|
||||
/// content-hash / revision check on next use) — this bus is <b>in-process, per
|
||||
/// node</b>; cross-node and failover propagation is the consumer's responsibility.
|
||||
/// See <c>docs/plans/2026-07-08-script-artifact-invalidation-contract.md</c>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="ArtifactKind">One of <see cref="ScriptArtifactKinds"/> — the kind of artifact that changed.</param>
|
||||
/// <param name="Names">The post-resolution (renamed) artifact names that changed.</param>
|
||||
/// <param name="Source">Origin of the change: <c>"BundleImport"</c>, <c>"Management"</c>, or <c>"FailoverActivation"</c>.</param>
|
||||
/// <param name="OccurredAtUtc">When the committing transaction completed.</param>
|
||||
public sealed record ScriptArtifactsChanged(
|
||||
string ArtifactKind,
|
||||
IReadOnlyList<string> Names,
|
||||
string Source,
|
||||
DateTimeOffset OccurredAtUtc);
|
||||
|
||||
/// <summary>
|
||||
/// The canonical set of <see cref="ScriptArtifactsChanged.ArtifactKind"/> values —
|
||||
/// the artifact classes that carry compiled/cached script and therefore need
|
||||
/// invalidation when their definition changes.
|
||||
/// </summary>
|
||||
public static class ScriptArtifactKinds
|
||||
{
|
||||
/// <summary>An Inbound API method (its script handler is compiled and cached).</summary>
|
||||
public const string ApiMethod = "ApiMethod";
|
||||
|
||||
/// <summary>A shared script (compiled inline at every call site that references it).</summary>
|
||||
public const string SharedScript = "SharedScript";
|
||||
|
||||
/// <summary>A template (its scripts flatten into every instance built from it).</summary>
|
||||
public const string Template = "Template";
|
||||
}
|
||||
Reference in New Issue
Block a user