feat(mesh): CentralCommunicationActor — dark-switched fan-out, DB-sourced contacts
Phase 2 Task 3. Central-side end of the boundary: routes every central->node command out over DPS or ClusterClient per MeshTransport:Mode, and forwards inbound ApplyAcks to the deploy coordinator singleton (Forward, not Tell, so the coordinator sees the node rather than this relay). Three things here are load-bearing and easy to get wrong later: SendToAll, never Send. Today's DPS publish reaches EVERY DriverHostActor and the node side has no ClusterId or node filter to compensate -- scoping happens later, inside the artifact. ClusterClient.Send delivers to exactly ONE registered actor, so it would deploy to a single node while every other node silently kept its old config, and the deployment could still seal green. Sabotage-verified: swapping to Send reddens exactly that one test. Exactly ONE ClusterClient, fleet-wide. A receptionist serves its whole cluster, so SendToAll reaches every registered node-comm actor in the mesh regardless of which contact point was dialled. One client per application Cluster -- the shape Phase 6 wants -- would fan each command out once per cluster while the fleet is still one mesh: N x duplicate DispatchDeployment and ApplyAck. Marked TODO(Phase 6). The contact set does NOT scope delivery. Excluding a maintenance-mode node from the contacts does not stop it receiving commands; it still receives them, as it does under today's broadcast. The filter is about which receptionists are worth dialling, not about who gets the message. Stated in the code because the opposite is the natural assumption. Also carries the sister project's shipped fixes: per-row address parsing so one malformed ClusterNode cannot abort the refresh and leave the contact set half-built (regression test orders the bad row FIRST), the cache entry cleared before recreate so a failed create cannot leave commands routing into a stopping actor, and a Status.Failure handler so a DB outage is a Warning rather than a silent debug-level unhandled message. Two test-harness bugs found and fixed while writing this, both mine: SubscribeAck goes to the SENDER (so the mediator subscribe needed an explicit sender), and EventFilter matches case-INSENSITIVELY, so a "was NOT" filter also caught this actor's own "was not created" warning. Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.Commons.Messages.Mesh;
|
||||
|
||||
/// <summary>
|
||||
/// Actor paths the two mesh comm actors register under. <b>These strings are the wire
|
||||
/// contract</b> of the central↔node boundary.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Declared once, here, rather than as literals on each side. The <c>deployments</c> /
|
||||
/// <c>deployment-acks</c> topic names are declared twice — once in
|
||||
/// <c>ConfigPublishCoordinator</c> and again in <c>DriverHostActor</c> — and agree only by
|
||||
/// convention; renaming one would compile, deploy, and deliver nothing. A ClusterClient path
|
||||
/// has the same failure mode and no compiler to catch it, so the constant is shared.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Nothing else pins these values, which is why <c>MeshCommActorPathTests</c> boots a real
|
||||
/// host and <c>Identify</c>-probes both paths.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public static class MeshPaths
|
||||
{
|
||||
/// <summary>Central-side comm actor — where a driver node sends its deployment acks.</summary>
|
||||
public const string CentralCommunication = "/user/central-communication";
|
||||
|
||||
/// <summary>Node-side comm actor — where central sends commands.</summary>
|
||||
public const string NodeCommunication = "/user/node-communication";
|
||||
|
||||
/// <summary>Actor name of <see cref="CentralCommunication"/> (the path's final segment).</summary>
|
||||
public const string CentralCommunicationName = "central-communication";
|
||||
|
||||
/// <summary>Actor name of <see cref="NodeCommunication"/> (the path's final segment).</summary>
|
||||
public const string NodeCommunicationName = "node-communication";
|
||||
}
|
||||
Reference in New Issue
Block a user