perf(runtime): split trigger evals from the blocking pool; bounded, deadline-aware execution

This commit is contained in:
Joseph Doherty
2026-08-14 22:36:15 -04:00
parent 312216ff2b
commit c4fc1f8ecd
42 changed files with 3673 additions and 1251 deletions
@@ -40,7 +40,6 @@ namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Scripts;
public class ScriptRuntimeContext
{
private readonly IActorRef _instanceActor;
private readonly IActorRef _self;
private readonly SharedScriptLibrary _sharedScriptLibrary;
private readonly int _currentCallDepth;
private readonly int _maxCallDepth;
@@ -50,7 +49,7 @@ public class ScriptRuntimeContext
/// <summary>
/// WaitForAttribute (spec §4.3): the per-script execution-timeout token from
/// the owning <c>ScriptExecutionActor</c>/<c>AlarmExecutionActor</c>
/// the owning script or alarm on-trigger run
/// (<c>cts.Token</c>). Bounds the <c>Attributes.WaitAsync</c> Ask so a script
/// that hits its own <c>ExecutionTimeoutSeconds</c> abandons the wait. Defaults
/// to <see cref="CancellationToken.None"/> for contexts that do not thread one
@@ -170,7 +169,6 @@ public class ScriptRuntimeContext
/// execution, external system calls, database access, and notification delivery.
/// </summary>
/// <param name="instanceActor">Reference to the Instance Actor managing this instance's state.</param>
/// <param name="self">Reference to the executing script actor.</param>
/// <param name="sharedScriptLibrary">Library containing shared scripts available to all instances.</param>
/// <param name="currentCallDepth">Current recursion depth of script calls.</param>
/// <param name="maxCallDepth">Maximum allowed recursion depth before an error is thrown.</param>
@@ -217,7 +215,6 @@ public class ScriptRuntimeContext
/// </param>
public ScriptRuntimeContext(
IActorRef instanceActor,
IActorRef self,
SharedScriptLibrary sharedScriptLibrary,
int currentCallDepth,
int maxCallDepth,
@@ -240,7 +237,6 @@ public class ScriptRuntimeContext
CancellationToken scriptTimeoutToken = default)
{
_instanceActor = instanceActor;
_self = self;
_sharedScriptLibrary = sharedScriptLibrary;
_currentCallDepth = currentCallDepth;
_maxCallDepth = maxCallDepth;
@@ -257,7 +253,7 @@ public class ScriptRuntimeContext
_operationTrackingStore = operationTrackingStore;
_cachedForwarder = cachedForwarder;
// SourceNode-stamping: the local node name read from
// INodeIdentityProvider at the ScriptExecutionActor; null when no
// INodeIdentityProvider at the launching script run; null when no
// provider was wired so the downstream callsites pass null through
// verbatim — leaving central SourceNode as NULL.
_sourceNode = sourceNode;
@@ -265,7 +261,7 @@ public class ScriptRuntimeContext
// (ParentExecutionId): stored verbatim — no `?? NewGuid()`
// fallback. A non-routed run legitimately has no parent and stays null.
_parentExecutionId = parentExecutionId;
// Optional — null when not wired (tests / AlarmExecutionActor).
// Optional — null when not wired (tests / alarm on-trigger runs).
_siteEventLogger = siteEventLogger;
// WaitForAttribute (spec §4.3): default(CancellationToken) == None when
// not threaded in — the WaitAsync Ask is then bounded only by its own timeout.
@@ -302,7 +298,6 @@ public class ScriptRuntimeContext
{
return new ScriptRuntimeContext(
_instanceActor,
_self,
_sharedScriptLibrary,
childCallDepth,
_maxCallDepth,
@@ -333,7 +328,7 @@ public class ScriptRuntimeContext
/// <summary>
/// Fire-and-forget emission of a <c>script</c> Error site event
/// for a recursion-limit violation. Mirrors the call shape used by
/// <c>ScriptExecutionActor</c>'s catch blocks. A fault from
/// the run's own catch blocks. A fault from
/// the site-event logger is observed-and-dropped (best-effort) via
/// <c>ContinueWith(OnlyOnFaulted)</c> — it never blocks or faults the
/// <c>_logger.LogError</c> + throw path that follows. A null logger is a no-op.
@@ -1135,7 +1130,7 @@ public class ScriptRuntimeContext
SourceSite: _siteId,
// SourceNode-stamping: the local node name
// (node-a/node-b) — threaded through INodeIdentityProvider
// at the ScriptExecutionActor; null when no provider was
// at the launching script run; null when no provider was
// wired so central persists SiteCalls.SourceNode as NULL.
SourceNode: _sourceNode,
Status: "Submitted",
@@ -1254,7 +1249,7 @@ public class ScriptRuntimeContext
SourceSite: _siteId,
// SourceNode-stamping: the local node name
// (node-a/node-b) — threaded through INodeIdentityProvider
// at the ScriptExecutionActor; null when no provider was
// at the launching script run; null when no provider was
// wired so central persists SiteCalls.SourceNode as NULL.
SourceNode: _sourceNode,
Status: "Attempted",
@@ -1322,7 +1317,7 @@ public class ScriptRuntimeContext
SourceSite: _siteId,
// SourceNode-stamping: the local node name
// (node-a/node-b) — threaded through INodeIdentityProvider
// at the ScriptExecutionActor; null when no provider was
// at the launching script run; null when no provider was
// wired so central persists SiteCalls.SourceNode as NULL.
SourceNode: _sourceNode,
Status: operationalTerminalStatus,
@@ -1913,7 +1908,7 @@ public class ScriptRuntimeContext
SourceSite: _siteId,
// SourceNode-stamping: the local node name
// (node-a/node-b) — threaded through INodeIdentityProvider
// at the ScriptExecutionActor; null when no provider was
// at the launching script run; null when no provider was
// wired so central persists SiteCalls.SourceNode as NULL.
SourceNode: _sourceNode,
Status: "Submitted",
@@ -2260,7 +2255,7 @@ public class ScriptRuntimeContext
OriginParentExecutionId: _parentExecutionId,
// SourceNode-stamping: the cluster node name on which this
// notification was emitted (node-a/node-b). Stamped from the local
// INodeIdentityProvider via ScriptExecutionActor. Rides inside the
// INodeIdentityProvider via the launching script run. Rides inside the
// serialized payload through the S&F buffer to central, where
// NotificationOutboxActor persists it on the Notifications row.
SourceNode: _sourceNode);