fix(scripting): quarantine a refusal behind a stuck orphan (fix round 2)
Ruling refinement on I1. Only timeouts are strikes, so a never-returning while(true), which times out once and is then only refused, was never quarantined, and that defeated E1. A refusal now quarantines immediately when the orphan it was refused behind has been executing for longer than ScriptingOptions.StuckOrphanQuarantineFactor x the script's timeout (default 10, so 20 s at the 2 s default; 0 or less disables it). It uses the same quarantine path: one Error, otopcua.script.quarantined with reason=stuck, Bad, lifted on source change or redeploy. A young orphan (a short overrun) is still a plain refusal. The guard stamps the run's start (Stopwatch timestamp) when the pool picks it up and clears it when the run really finishes. Tests: the 30-trigger while(true) regression (paced) now ends quarantined with reason "stuck", still with exactly one orphan and a healthy sibling. Positive control: a 2x overrun is refused, not quarantined, and evaluates again once the orphan completes. A factor of 0 disables the rule. Docs (ScriptEditor "Runtime safety", VirtualTags) and the seam remarks are updated. Refs #734 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -42,7 +42,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Calculation;
|
||||
/// <b>Run quarantine.</b> Every compiled run goes through one <see cref="ScriptRunGuard"/> keyed by
|
||||
/// calc-tag RawPath with the script source as the identity: a run is refused while the tag's previous
|
||||
/// (timed-out, abandoned) run is still executing, and the tag is quarantined after three consecutive
|
||||
/// timeouts (a refusal is Bad but not a strike) or an allocation-budget breach — both surface as a <see cref="VirtualTagEvalResult.Failure"/>
|
||||
/// timeouts (a refusal is Bad but not a strike, unless its orphan is stuck past StuckOrphanQuarantineFactor × the budget) or an allocation-budget breach — both surface as a <see cref="VirtualTagEvalResult.Failure"/>
|
||||
/// the driver maps to Bad. The driver's evaluation pump awaits <see cref="EvaluateAsync"/> rather than
|
||||
/// blocking a pool thread on the sync <see cref="Evaluate(string, string, IReadOnlyDictionary{string, DataValueSnapshot})"/>,
|
||||
/// and the guard starts the budget clock only once the pool has picked the script up, so pool starvation
|
||||
|
||||
Reference in New Issue
Block a user