Script runner load timeout counts the time a load waits behind other compiles #790
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while fixing the compile-burst heartbeat starvation (lmxopcua#780, 2026-11-10).
In
OutOfProcessScriptRunner.RunAsync, each caller waits at mostLoadTimeout(60 s) forEnsureLoadedAsync(...). That clock starts when the host asks for the load. The worker now compiles onmin(8, max(1, CPUs/2))dedicated threads, so a load can sit in the worker's queue behind hundreds of others.On windev, 1,500 cold compiles on one shard take about 18 s. A larger cold load can therefore push the last keys past 60 s while no compile is actually stuck: a big node start with an empty PE cache, or a slower box. When that happens, the runner kills the worker with
KilledLoadTimeoutand strikes the key whose timer fired. That key is innocent; it was only queued. Every other key in flight becomes a victim.Fix shape.
LoadStartedframe, or a per-outcome compile-duration field), and apply the timeout from that moment.Pin it with a test that queues more compiles than fit in
LoadTimeoutand asserts no kill and no strike.Fixed on
master@8582ce91.LoadStarted { load_id }frame.LoadTimeoutafter it started kills the worker. Only that key takes the strike, throughLoadEntry.TimedOut→KilledLoadTimeout, and the caller getscompile failure: compile did not finish within N s.Hello.compile_threadsis a test knob; the default is 0, which keeps the worker's own default.Tests (
SupervisionTests):Compiles_queued_behind_others_longer_than_the_load_timeout_are_not_killed_or_struckcompile did not finish.A_compile_still_running_a_load_timeout_after_it_started_is_killed_and_struck(positive control)KilledLoadTimeoutnaming that key, twice, and then quarantine.Both pass on macOS and on windev. All suites pass; see #789 for the numbers. Closing.