feat(scripting): bind the Scripting section node-wide and clamp its knobs
Program.cs binds ScriptingOptions from Scripting:* once, clamps every numeric knob through ScriptingOptions.Sanitized (logging a Warning per adjustment) and registers the one instance. It now reaches all three script seams: RoslynVirtualTagEvaluator, the scripted-alarm engine built in DriverHostActor (new trailing Props parameter, wired in WithOtOpcUaRuntimeActors) and every Calculation driver (node options as the base, per-driver config keys override one knob on a copy). ScriptRunGuard sanitizes again in its ctor and computes the stuck threshold with a saturating multiply, so an absurd StuckOrphanQuarantineFactor can no longer throw OverflowException on a refused run. Refs #731 #734 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -96,9 +96,11 @@ public sealed class ScriptRunGuard
|
||||
/// <param name="logger">Where the quarantine Error line goes; null ⇒ Serilog's global logger.</param>
|
||||
public ScriptRunGuard(ScriptingOptions? options = null, ILogger? logger = null)
|
||||
{
|
||||
options ??= new ScriptingOptions();
|
||||
// Clamped here as well as at the bind site, because options also arrive from a Calculation driver's own
|
||||
// config and from tests. An unclamped factor made the refusal path's timeout * factor overflow.
|
||||
options = (options ?? new ScriptingOptions()).Sanitized(out _);
|
||||
_maxAllocBytesPerRun = options.MaxAllocBytesPerRun;
|
||||
_quarantineThreshold = Math.Max(1, options.QuarantineAfterConsecutiveTimeouts);
|
||||
_quarantineThreshold = options.QuarantineAfterConsecutiveTimeouts;
|
||||
_stuckFactor = options.StuckOrphanQuarantineFactor;
|
||||
_logger = logger ?? Log.Logger;
|
||||
}
|
||||
@@ -197,7 +199,11 @@ public sealed class ScriptRunGuard
|
||||
if (_stuckFactor > 0 && Volatile.Read(ref state.RunStartedTimestamp) is var startedAt and not 0)
|
||||
{
|
||||
var running = Stopwatch.GetElapsedTime(startedAt);
|
||||
var threshold = timeout * _stuckFactor;
|
||||
// Saturating: even the clamped maximum factor times a huge timeout must not overflow TimeSpan.
|
||||
var thresholdTicks = timeout.Ticks * _stuckFactor;
|
||||
var threshold = thresholdTicks >= TimeSpan.MaxValue.Ticks
|
||||
? TimeSpan.MaxValue
|
||||
: TimeSpan.FromTicks((long)thresholdTicks);
|
||||
if (running > threshold)
|
||||
{
|
||||
Quarantine(key, state,
|
||||
|
||||
Reference in New Issue
Block a user