fix(runtime): pin the Primary-verdict member-event subscription with a test; document the pre-join allow window (review R6 MINOR-2/3)
MINOR-3: new DriverHostActorPrimaryRoleSourceTests case drives the deny flip with a real ClusterEvent.MemberUp on the EventStream (how the cluster's domain-event publisher reaches a Cluster.Subscribe subscriber) instead of a direct RepublishPrimaryVerdict tell; it fails when the Cluster.Subscribe(IMemberEvent) call is deleted. MINOR-2: the published verdict MIRRORS the live gate; before this node has joined its member count is 0 and both allow (seconds; up to the bootstrap guard's 25 s probe), so the Sparkplug primary-host claim can be held on both nodes in that window (native ack is unaffected - view and route agree). Behaviour deliberately unchanged: denying until self is Up would change the live gate too and delay writes/acks on a single-node cluster's own join. Comments + AlarmTracking.md / Redundancy.md / Mqtt.md corrected. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
This commit is contained in:
+25
@@ -66,6 +66,31 @@ public sealed class DriverHostActorPrimaryRoleSourceTests : RuntimeActorTestBase
|
||||
AwaitAssert(() => source.Published.ShouldBe([true, false]), duration: Timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Review R6 MINOR-3 — the same flip driven by a real cluster MEMBER EVENT rather than a direct
|
||||
/// <see cref="DriverHostActor.RepublishPrimaryVerdict"/> tell, so it fails if the host's
|
||||
/// <c>Cluster.Subscribe(… IMemberEvent)</c> or its <c>IMemberEvent</c> handler is deleted. The event is published
|
||||
/// on the ActorSystem EventStream, which is exactly how the cluster's domain-event publisher delivers it to a
|
||||
/// <c>Cluster.Subscribe</c> subscriber — and to nothing else. Re-published inside the wait because the
|
||||
/// subscription is registered asynchronously by the publisher actor after <c>PreStart</c>.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void A_cluster_member_event_flips_the_published_verdict_without_a_direct_republish()
|
||||
{
|
||||
var source = new RecordingPrimaryRoleSource();
|
||||
var members = 1;
|
||||
SpawnHost(source, () => Volatile.Read(ref members));
|
||||
AwaitAssert(() => source.Published.ShouldBe([true]), duration: Timeout);
|
||||
|
||||
Volatile.Write(ref members, 2);
|
||||
var memberUp = new Akka.Cluster.ClusterEvent.MemberUp(Akka.Cluster.Cluster.Get(Sys).SelfMember);
|
||||
AwaitAssert(() =>
|
||||
{
|
||||
Sys.EventStream.Publish(memberUp);
|
||||
source.Published.ShouldBe([true, false]);
|
||||
}, duration: Timeout, interval: TimeSpan.FromMilliseconds(100));
|
||||
}
|
||||
|
||||
private IActorRef SpawnHost(IDriverPrimaryRoleSource source, Func<int> driverMemberCount) =>
|
||||
Sys.ActorOf(DriverHostActor.Props(
|
||||
NewInMemoryDbFactory(),
|
||||
|
||||
Reference in New Issue
Block a user