merge: startup reconcile starts the healed InstanceActor (register row 67) — EnsureInstanceStartedCommand to the DM singleton, idempotent, disable-wins, Warning site event on self-heal

This commit is contained in:
Joseph Doherty
2026-08-15 17:56:21 -04:00
7 changed files with 631 additions and 9 deletions
@@ -0,0 +1,29 @@
namespace ZB.MOM.WW.ScadaBridge.Commons.Messages.Deployment;
/// <summary>
/// Site-internal request to make sure an already-persisted instance is actually RUNNING.
/// Routes via the deployment-manager singleton proxy so the Instance Actor is only ever
/// created under the singleton, whichever node raised the request.
/// <para>
/// Emitted by <c>SiteReconciliationActor</c> after its node-STARTUP pass fetches and stores
/// a config the node was missing. The reconcile heal path writes the FILE; without this the
/// runtime was left untouched, so an instance whose config was absent at boot (lost volume,
/// first boot after a restore, rehomed data dir) stayed dead until the NEXT restart, whose
/// SQLite load finally started it.
/// </para>
/// <para>
/// <b>Fire-and-forget and idempotent.</b> There is no reply: the handler no-ops when the
/// instance is already running, when an in-flight deploy will create it anyway, or when the
/// durable row says the instance is disabled. The stored row — not this message — is the
/// authority on both the config body and enabled/disabled state, so a disable that landed
/// after the reconcile fetch still wins.
/// </para>
/// </summary>
/// <param name="InstanceUniqueName">Unique name of the instance that should be running.</param>
/// <param name="Reason">
/// Short human-readable provenance for the request (e.g. <c>"startup reconcile"</c>), carried
/// verbatim into the log line and the operational site event so the heal is not silent.
/// </param>
public record EnsureInstanceStartedCommand(
string InstanceUniqueName,
string Reason);