fix(deployment): drop dead ITemplateGraphWatermark ctor param and no-op ClearMemos from StaleInstanceProbe (review 2026-10-21 04/U2)
This commit is contained in:
@@ -1,21 +1,19 @@
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Transport;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.DeploymentManager;
|
||||
|
||||
/// <summary>Recomputes deployment revisions from authoritative configuration on every probe.
|
||||
/// Process-local watermarks cannot prove freshness after another central changes the shared store.</summary>
|
||||
/// Process-local watermarks cannot prove freshness after another central changes the shared store,
|
||||
/// so nothing is memoised across calls.</summary>
|
||||
public sealed class StaleInstanceProbe : IStaleInstanceProbe
|
||||
{
|
||||
private readonly IFlatteningPipeline _flatteningPipeline;
|
||||
|
||||
/// <summary>Initializes the authoritative probe. Watermark remains a constructor compatibility dependency.</summary>
|
||||
/// <summary>Initializes the authoritative probe.</summary>
|
||||
/// <param name="flatteningPipeline">The pipeline used to flatten instances for staleness comparison.</param>
|
||||
/// <param name="watermark">The template graph watermark; retained only for constructor compatibility.</param>
|
||||
public StaleInstanceProbe(IFlatteningPipeline flatteningPipeline, ITemplateGraphWatermark watermark)
|
||||
public StaleInstanceProbe(IFlatteningPipeline flatteningPipeline)
|
||||
{
|
||||
_flatteningPipeline = flatteningPipeline ?? throw new ArgumentNullException(nameof(flatteningPipeline));
|
||||
ArgumentNullException.ThrowIfNull(watermark);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -26,7 +24,4 @@ public sealed class StaleInstanceProbe : IStaleInstanceProbe
|
||||
validateScripts: false, session).ConfigureAwait(false);
|
||||
return result.IsSuccess ? result.Value.RevisionHash : null;
|
||||
}
|
||||
|
||||
/// <summary>Compatibility hook: probes no longer retain process-global results.</summary>
|
||||
public static void ClearMemos() { }
|
||||
}
|
||||
|
||||
@@ -717,16 +717,12 @@ public class DeploymentServiceTests : TestKit
|
||||
public async Task StaleInstanceProbe_RequestsValidateScriptsFalse()
|
||||
{
|
||||
// The Transport stale-instance probe also only needs the hash — same skip.
|
||||
// The probe memoises per-instance against the graph watermark, so start
|
||||
// from a clean memo or a sibling test's entry would satisfy the probe
|
||||
// without a flatten at all.
|
||||
StaleInstanceProbe.ClearMemos();
|
||||
|
||||
_pipeline.CreateSession().Returns(_ => new FlattenSession(new TemplateGraphWatermark()));
|
||||
_pipeline.FlattenAndValidateAsync(5, Arg.Any<CancellationToken>(), Arg.Any<bool>(), Arg.Any<FlattenSession?>())
|
||||
.Returns(Result<FlatteningPipelineResult>.Success(
|
||||
new FlatteningPipelineResult(new FlattenedConfiguration(), "sha256:probe", ValidationResult.Success())));
|
||||
var probe = new StaleInstanceProbe(_pipeline, new TemplateGraphWatermark());
|
||||
var probe = new StaleInstanceProbe(_pipeline);
|
||||
|
||||
var hash = await probe.GetCurrentRevisionHashAsync(5);
|
||||
|
||||
|
||||
@@ -8,20 +8,11 @@ using ZB.MOM.WW.ScadaBridge.TemplateEngine.Flattening;
|
||||
namespace ZB.MOM.WW.ScadaBridge.DeploymentManager.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// The staleness fast path: <see cref="StaleInstanceProbe"/> memoises a computed
|
||||
/// revision hash against the <see cref="ITemplateGraphWatermark"/> readings it was
|
||||
/// computed under, and the memo is PROCESS-STATIC. That makes the watermark the
|
||||
/// only thing standing between a cached hash and a wrong answer — so these tests
|
||||
/// pin that the memo is served only while the watermark has not moved, and is
|
||||
/// dropped the moment it has.
|
||||
///
|
||||
/// <para>
|
||||
/// The failure this guards against is a real one: a data-connection edit, or a
|
||||
/// bundle import committing through the raw <c>DbContext</c>, changes the flattened
|
||||
/// output without going through the repository path that derives bumps from the
|
||||
/// change tracker. If that write does not bump, the memo below keeps answering with
|
||||
/// the old hash forever.
|
||||
/// </para>
|
||||
/// <see cref="StaleInstanceProbe"/> is authoritative: it re-flattens on EVERY probe and
|
||||
/// memoises nothing across calls. It used to memoise a revision hash against the
|
||||
/// process-local <see cref="ITemplateGraphWatermark"/>, which a peer central node writing
|
||||
/// the shared database could never bump (MG-3) — these tests pin that every probe sees
|
||||
/// the current configuration whatever the local watermark says.
|
||||
/// </summary>
|
||||
public class StaleInstanceProbeTests
|
||||
{
|
||||
@@ -35,9 +26,6 @@ public class StaleInstanceProbeTests
|
||||
/// <summary>Initializes a new instance of the <c>StaleInstanceProbeTests</c> class.</summary>
|
||||
public StaleInstanceProbeTests()
|
||||
{
|
||||
// Process-static memo: start every test from a clean slate.
|
||||
StaleInstanceProbe.ClearMemos();
|
||||
|
||||
_pipeline.CreateSession().Returns(_ => new FlattenSession(_watermark));
|
||||
_pipeline
|
||||
.FlattenAndValidateAsync(InstanceId, Arg.Any<CancellationToken>(), Arg.Any<bool>(), Arg.Any<FlattenSession?>())
|
||||
@@ -50,7 +38,20 @@ public class StaleInstanceProbeTests
|
||||
});
|
||||
}
|
||||
|
||||
private StaleInstanceProbe CreateProbe() => new(_pipeline, _watermark);
|
||||
private StaleInstanceProbe CreateProbe() => new(_pipeline);
|
||||
|
||||
/// <summary>
|
||||
/// review 2026-10-21 04/U2: with the memo gone the probe has no use for the watermark, so
|
||||
/// its only dependency is the pipeline and the no-op <c>ClearMemos</c> hook is gone.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Probe_DependsOnlyOnThePipeline_AndHasNoMemoHook()
|
||||
{
|
||||
var ctor = Assert.Single(typeof(StaleInstanceProbe).GetConstructors());
|
||||
var parameter = Assert.Single(ctor.GetParameters());
|
||||
Assert.Equal(typeof(IFlatteningPipeline), parameter.ParameterType);
|
||||
Assert.Null(typeof(StaleInstanceProbe).GetMethod("ClearMemos"));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that peer edit with independent watermark is observed by warm active probe.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
|
||||
-4
@@ -1595,10 +1595,6 @@ public sealed class BundleImporterApplyTests : IDisposable
|
||||
[Fact]
|
||||
public async Task ApplyAsync_second_overwrite_of_same_template_still_marks_instance_stale()
|
||||
{
|
||||
// The memo is process-static and keyed by instance id alone; start clean so
|
||||
// this test does not inherit another class's entry.
|
||||
StaleInstanceProbe.ClearMemos();
|
||||
|
||||
await SeedSiteAsync();
|
||||
|
||||
// Shape A → bundle A.
|
||||
|
||||
Reference in New Issue
Block a user