fix(vtags): respawn equipment virtualtag child on in-place plan change (H1b, stillpending §1)
This commit is contained in:
@@ -39,6 +39,9 @@ public sealed class VirtualTagHostActor : ReceiveActor
|
||||
private readonly Dictionary<string, IActorRef> _children = new(StringComparer.Ordinal);
|
||||
// vtagId -> folder-scoped OPC UA NodeId the materialiser placed the variable at.
|
||||
private readonly Dictionary<string, string> _nodeIdByVtag = new(StringComparer.Ordinal);
|
||||
// vtagId -> the plan its currently-spawned child was built from, so we can detect an in-place
|
||||
// change (edited Expression/DependencyRefs) and stop+respawn the child to adopt it.
|
||||
private readonly Dictionary<string, EquipmentVirtualTagPlan> _planByVtag = new(StringComparer.Ordinal);
|
||||
|
||||
/// <summary>Factory method to create Props for a VirtualTagHostActor.</summary>
|
||||
/// <param name="publishActor">The OPC UA publish actor that consumes
|
||||
@@ -78,6 +81,22 @@ public sealed class VirtualTagHostActor : ReceiveActor
|
||||
_children.Remove(vtagId);
|
||||
}
|
||||
|
||||
// Stop + forget children whose plan changed in place (edited Expression/DependencyRefs, or a
|
||||
// toggled flag). EquipmentVirtualTagPlan has element-wise value equality, so an identical
|
||||
// redeploy diffs equal and is left untouched. Forgetting the child here lets the spawn-new
|
||||
// loop below recreate it from the new plan — children are auto-named (no explicit name), so a
|
||||
// stop+respawn cannot hit the "actor name not unique" collision.
|
||||
foreach (var p in msg.Plans)
|
||||
{
|
||||
if (_children.ContainsKey(p.VirtualTagId)
|
||||
&& _planByVtag.TryGetValue(p.VirtualTagId, out var prev)
|
||||
&& !prev.Equals(p))
|
||||
{
|
||||
Context.Stop(_children[p.VirtualTagId]); // PostStop unregisters the old mux interest.
|
||||
_children.Remove(p.VirtualTagId);
|
||||
}
|
||||
}
|
||||
|
||||
// Rebuild the NodeId map every apply so renames (Name/FolderPath/EquipmentId changes) are
|
||||
// picked up. The map only contains currently-desired vtags, so a result for a removed vtag
|
||||
// finds no entry and is dropped.
|
||||
@@ -87,15 +106,13 @@ public sealed class VirtualTagHostActor : ReceiveActor
|
||||
_nodeIdByVtag[p.VirtualTagId] = NodeIdFor(p);
|
||||
}
|
||||
|
||||
// Spawn children for new vtagIds only — existing children keep their mux subscriptions and
|
||||
// last-value dedup state. Expression/dependency changes on an existing vtag are NOT
|
||||
// re-applied here; the loader's vtags are stable, and a future enhancement can stop+respawn
|
||||
// a child whose plan changed (the diff already identifies ChangedEquipmentVirtualTags).
|
||||
// Spawn children for vtagIds that have no live child. This covers genuinely-new vtags AND any
|
||||
// vtag whose child was just forgotten above because its plan changed in place — that child is
|
||||
// recreated here from the new plan, adopting the edited Expression/DependencyRefs. Children
|
||||
// whose plan was unchanged still have a live entry and are skipped, keeping their mux
|
||||
// subscriptions and last-value dedup state.
|
||||
foreach (var p in msg.Plans)
|
||||
{
|
||||
// TODO(equipment-virtualtags): when a plan's Expression/DependencyRefs change in place
|
||||
// (ChangedEquipmentVirtualTags), stop+respawn the child here; today only spawn-new/stop-removed
|
||||
// is handled (loader vtags are stable).
|
||||
if (_children.ContainsKey(p.VirtualTagId)) continue;
|
||||
|
||||
// Auto-name the child: vtagIds can contain characters illegal in actor names, so let Akka
|
||||
@@ -113,6 +130,14 @@ public sealed class VirtualTagHostActor : ReceiveActor
|
||||
_log.Debug("VirtualTagHost: spawned child for vtag {VirtualTagId}", p.VirtualTagId);
|
||||
}
|
||||
|
||||
// Refresh the plan map to exactly the desired set so the next apply can detect in-place
|
||||
// changes against what each live child was actually built from.
|
||||
_planByVtag.Clear();
|
||||
foreach (var p in msg.Plans)
|
||||
{
|
||||
_planByVtag[p.VirtualTagId] = p;
|
||||
}
|
||||
|
||||
_log.Debug("VirtualTagHost: applied (desired={Desired}, children={Children})",
|
||||
desired.Count, _children.Count);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user