fix(site-runtime): InstanceActor retries failed/lost tag subscriptions per connection (S4/UA6) — closes the unknown-connection ordering race
This commit is contained in:
@@ -1171,4 +1171,69 @@ public class InstanceActorTests : TestKit, IDisposable
|
||||
Assert.Single(overrides);
|
||||
Assert.Equal("[\"a\"", overrides["Counts"]);
|
||||
}
|
||||
|
||||
// ── S4/UA6: tag-subscription retry (failed AND lost responses) ──
|
||||
|
||||
/// <summary>
|
||||
/// Builds an Instance Actor with a single data-sourced attribute and the given
|
||||
/// options (so the retry interval is short), returning it plus the DCL probe.
|
||||
/// The initial SubscribeTagsRequest is left in the probe's queue for the caller.
|
||||
/// </summary>
|
||||
private (IActorRef Instance, TestProbe Dcl) CreateInstanceWithDataSourcedAttribute(SiteRuntimeOptions options)
|
||||
{
|
||||
var config = new FlattenedConfiguration
|
||||
{
|
||||
InstanceUniqueName = "Sub-1",
|
||||
Attributes =
|
||||
[
|
||||
new ResolvedAttribute
|
||||
{
|
||||
CanonicalName = "Motor.Temp", Value = "0", DataType = "Int",
|
||||
DataSourceReference = "ns=2;s=Motor.Temp", BoundDataConnectionName = "conn-1"
|
||||
}
|
||||
]
|
||||
};
|
||||
var dcl = CreateTestProbe();
|
||||
var actor = ActorOf(Props.Create(() => new InstanceActor(
|
||||
"Sub-1",
|
||||
JsonSerializer.Serialize(config),
|
||||
_storage,
|
||||
_compilationService,
|
||||
_sharedScriptLibrary,
|
||||
null,
|
||||
options,
|
||||
NullLogger<InstanceActor>.Instance,
|
||||
dcl.Ref)));
|
||||
return (actor, dcl);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FailedSubscribeResponse_IsRetried()
|
||||
{
|
||||
var options = new SiteRuntimeOptions { TagSubscribeRetryIntervalMs = 200 };
|
||||
var (instance, dclProbe) = CreateInstanceWithDataSourcedAttribute(options);
|
||||
|
||||
var first = dclProbe.ExpectMsg<SubscribeTagsRequest>();
|
||||
instance.Tell(new SubscribeTagsResponse(first.CorrelationId, first.InstanceUniqueName,
|
||||
false, "Unknown connection: conn-1", DateTimeOffset.UtcNow), dclProbe.Ref);
|
||||
|
||||
var retry = dclProbe.ExpectMsg<SubscribeTagsRequest>(TimeSpan.FromSeconds(5)); // S4 core
|
||||
Assert.Equal(first.ConnectionName, retry.ConnectionName);
|
||||
Assert.Equal(first.TagPaths, retry.TagPaths);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LostSubscribeResponse_IsRetried_AndSuccessStopsRetrying()
|
||||
{
|
||||
var options = new SiteRuntimeOptions { TagSubscribeRetryIntervalMs = 200 };
|
||||
var (instance, dclProbe) = CreateInstanceWithDataSourcedAttribute(options);
|
||||
|
||||
dclProbe.ExpectMsg<SubscribeTagsRequest>();
|
||||
// No reply at all (dead-lettered response) -> must re-send.
|
||||
var retry = dclProbe.ExpectMsg<SubscribeTagsRequest>(TimeSpan.FromSeconds(5));
|
||||
|
||||
instance.Tell(new SubscribeTagsResponse(retry.CorrelationId, retry.InstanceUniqueName,
|
||||
true, null, DateTimeOffset.UtcNow), dclProbe.Ref);
|
||||
dclProbe.ExpectNoMsg(TimeSpan.FromMilliseconds(600)); // retry timer cancelled
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user