feat(scripting): expose the run token to scripts as ctx.CancellationToken
ScriptContext.CancellationToken is backed by an AsyncLocal that ScriptEvaluator.RunAsync scopes around the compiled delegate, so it is exactly the token ScriptRunGuard cancels on timeout. A polling script can now end its own abandoned run and free the slot. AsyncLocal rather than a field because the scripted-alarm engine reuses one context per alarm: an orphan keeps seeing its own cancelled token. The scoping entry point is internal (IVT to Core.Scripting) so a script cannot replace its own token. Editor parity: ScriptAnalysisService dot-completion now walks the receiver's base chain (instance members only, stopping before System.Object). Before this, a member declared only on ScriptContext compiled and published but never completed. DiagnoseTests pins the member as allow-listed; CompletionTests pins the completion. Refs #731 #734 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -198,6 +198,13 @@ scripted-alarm predicates) runs scripts through the shared `ScriptRunGuard`:
|
||||
2 s default) quarantines immediately, through the same path (Error log, metric
|
||||
`reason=stuck`, Bad). A short overrun (a young orphan) stays a plain refusal and
|
||||
the script resumes once the orphan completes.
|
||||
- **Cooperative cancellation (`ctx.CancellationToken`).** The guard cancels the run
|
||||
token when a run times out, and scripts see it as `ctx.CancellationToken`. A
|
||||
long-running loop that polls `ctx.CancellationToken.IsCancellationRequested` (or calls
|
||||
`ctx.CancellationToken.ThrowIfCancellationRequested()`) ends its own abandoned run
|
||||
and frees the slot, instead of holding a pool thread until it returns. A script that
|
||||
ignores the token is still an orphan. The editor completes the member, and
|
||||
`CancellationToken` is on the sandbox allow-list.
|
||||
- **Allocation budget.** A single run allocating more than
|
||||
`Scripting:MaxAllocBytesPerRun` (64 MB) is quarantined. This is sampled after the
|
||||
run returns, so a run that OOMs the process first is not stopped — that needs an
|
||||
|
||||
Reference in New Issue
Block a user