fix(r2-04): AddressSpaceApplyOutcome carries RebuildFailed/FailedNodes; SafeRebuild returns bool (01/S-1)
This commit is contained in:
@@ -146,10 +146,11 @@ public sealed class AddressSpaceApplier
|
||||
// covered for free and need no separate surgical pass.
|
||||
var renamedFolders = plan.RenamedFolders;
|
||||
var rebuilt = false;
|
||||
var rebuildFailed = false;
|
||||
|
||||
if (structuralRebuild)
|
||||
{
|
||||
SafeRebuild();
|
||||
rebuildFailed = !SafeRebuild();
|
||||
rebuilt = true;
|
||||
}
|
||||
else if (surgicalTagDeltas.Count > 0 || renamedFolders.Count > 0)
|
||||
@@ -188,12 +189,12 @@ public sealed class AddressSpaceApplier
|
||||
}
|
||||
if (!ok) { allApplied = false; break; }
|
||||
}
|
||||
if (!allApplied) { SafeRebuild(); rebuilt = true; }
|
||||
if (!allApplied) { rebuildFailed = !SafeRebuild(); rebuilt = true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sink lacks the surgical capability ⇒ rebuild (safe default).
|
||||
SafeRebuild();
|
||||
rebuildFailed = !SafeRebuild();
|
||||
rebuilt = true;
|
||||
}
|
||||
}
|
||||
@@ -212,7 +213,7 @@ public sealed class AddressSpaceApplier
|
||||
// currently-historized set. Same non-blocking + throw-safe discipline as the provisioning hook.
|
||||
FeedHistorizedRefs(plan);
|
||||
|
||||
return new AddressSpaceApplyOutcome(removedCount, addedCount, changedCount, rebuilt);
|
||||
return new AddressSpaceApplyOutcome(removedCount, addedCount, changedCount, rebuilt, rebuildFailed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -370,15 +371,22 @@ public sealed class AddressSpaceApplier
|
||||
string.IsNullOrWhiteSpace(tag.HistorianTagname) ? tag.FullName : tag.HistorianTagname)
|
||||
: null;
|
||||
|
||||
private void SafeRebuild()
|
||||
/// <summary>Rebuild the sink's address space, swallowing (and Error-logging) any fault.
|
||||
/// Returns <c>true</c> on success, <c>false</c> when the sink threw — the caller threads the
|
||||
/// result into <see cref="AddressSpaceApplyOutcome.RebuildFailed"/> so a broken rebuild is
|
||||
/// visible instead of reported as optimistic success (archreview 01/S-1).</summary>
|
||||
/// <returns><c>true</c> when the rebuild completed; <c>false</c> when the sink threw.</returns>
|
||||
private bool SafeRebuild()
|
||||
{
|
||||
try
|
||||
{
|
||||
_sink.RebuildAddressSpace();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "AddressSpaceApplier: sink.RebuildAddressSpace threw");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -687,9 +695,18 @@ public sealed class AddressSpaceApplier
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Summary of one apply pass. Useful for tests + audit-log entries on the deploy path.</summary>
|
||||
/// <summary>Summary of one apply pass. Useful for tests + audit-log entries on the deploy path.
|
||||
/// <para><see cref="RebuildCalled"/> means a rebuild was ATTEMPTED; <see cref="RebuildFailed"/> means the
|
||||
/// attempt threw (the sink's address space is now stale/partial). <see cref="FailedNodes"/> counts
|
||||
/// swallowed per-node sink failures in <see cref="AddressSpaceApplier.Apply"/>'s own passes (the removal
|
||||
/// alarm-condition writes). The <c>Materialise*</c> passes report their own failed-node tallies via their
|
||||
/// <c>int</c> returns — the publish actor sums both channels so a degraded apply is operator-visible
|
||||
/// (Error log + <c>otopcua.opcua.apply.failed</c> meter) instead of reported as optimistic success
|
||||
/// (archreview 01/S-1). New trailing fields are defaulted so every existing construction compiles.</para></summary>
|
||||
public sealed record AddressSpaceApplyOutcome(
|
||||
int RemovedNodes,
|
||||
int AddedNodes,
|
||||
int ChangedNodes,
|
||||
bool RebuildCalled);
|
||||
bool RebuildCalled,
|
||||
bool RebuildFailed = false,
|
||||
int FailedNodes = 0);
|
||||
|
||||
Reference in New Issue
Block a user