feat(runtime): VirtualTagActor skeleton (engine wiring tracked as F8)

This commit is contained in:
Joseph Doherty
2026-05-26 05:09:01 -04:00
parent 64c627f8d6
commit 39729bfe21
2 changed files with 63 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
using Akka.Actor;
using Akka.Event;
using ZB.MOM.WW.OtOpcUa.Commons.Types;
namespace ZB.MOM.WW.OtOpcUa.Runtime.VirtualTags;
/// <summary>
/// Wraps a single virtual-tag expression. Receives dependency-tag updates, recomputes the
/// expression, and publishes the result to <c>OpcUaPublishActor</c>.
///
/// Engine wiring (compile expression via <c>VirtualTagEngine</c>, manage subscriptions,
/// emit <c>AttributeValueUpdate</c>) is staged for follow-up F8. This skeleton compiles + has
/// a basic message contract so DriverHostActor can spawn it as a child.
/// </summary>
public sealed class VirtualTagActor : ReceiveActor
{
public sealed record DependencyValueChanged(string TagId, object? Value, DateTime TimestampUtc);
public sealed record EvaluationResult(string VirtualTagId, object? Value, DateTime TimestampUtc, CorrelationId Correlation);
private readonly string _virtualTagId;
private readonly string _expression;
private readonly ILoggingAdapter _log = Context.GetLogger();
private readonly Dictionary<string, object?> _dependencies = new(StringComparer.Ordinal);
public static Props Props(string virtualTagId, string expression) =>
Akka.Actor.Props.Create(() => new VirtualTagActor(virtualTagId, expression));
public VirtualTagActor(string virtualTagId, string expression)
{
_virtualTagId = virtualTagId;
_expression = expression;
Receive<DependencyValueChanged>(msg =>
{
_dependencies[msg.TagId] = msg.Value;
// Engine wiring (F8): VirtualTagEngine.Evaluate(_expression, _dependencies) → publish.
_log.Debug("VirtualTag {Id}: dependency {Tag}={Value} buffered (eval staged for F8)",
_virtualTagId, msg.TagId, msg.Value);
});
}
}

View File

@@ -0,0 +1,22 @@
using Akka.Actor;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Runtime.Tests.Harness;
using ZB.MOM.WW.OtOpcUa.Runtime.VirtualTags;
namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.VirtualTags;
public sealed class VirtualTagActorTests : RuntimeActorTestBase
{
[Fact]
public void DependencyValueChanged_is_accepted_and_actor_stays_alive()
{
var actor = Sys.ActorOf(VirtualTagActor.Props("vt-1", "a + b"));
Watch(actor);
actor.Tell(new VirtualTagActor.DependencyValueChanged("tag-a", 10, DateTime.UtcNow));
actor.Tell(new VirtualTagActor.DependencyValueChanged("tag-b", 20, DateTime.UtcNow));
// No crash, no termination.
ExpectNoMsg(TimeSpan.FromMilliseconds(200));
}
}