feat(site-runtime): script scheduler gauges — queue depth, busy threads, oldest-busy age (S2/UA5)

This commit is contained in:
Joseph Doherty
2026-07-08 23:35:09 -04:00
parent b83d1ed19c
commit 474ec8a221
2 changed files with 85 additions and 3 deletions
@@ -44,4 +44,34 @@ public class ScriptExecutionSchedulerTests
var b = ScriptExecutionScheduler.Shared(options);
Assert.Same(a, b);
}
// SiteRuntime-S2/UA5: the scheduler exposes observability gauges so a stuck /
// saturated script-execution pool is visible to operators via site health.
[Fact]
public async Task Gauges_ReflectBusyThreadAndQueueDepth()
{
using var scheduler = new ScriptExecutionScheduler(1);
using var gate = new ManualResetEventSlim(false);
var blocking = Task.Factory.StartNew(() => gate.Wait(),
CancellationToken.None, TaskCreationOptions.None, scheduler);
var queued = Task.Factory.StartNew(() => { },
CancellationToken.None, TaskCreationOptions.None, scheduler);
await WaitUntilAsync(() => scheduler.BusyThreadCount == 1);
Assert.Equal(1, scheduler.QueueDepth); // second task waiting
Assert.True(scheduler.OldestBusyAge > TimeSpan.Zero);
gate.Set();
await Task.WhenAll(blocking, queued);
await WaitUntilAsync(() => scheduler.BusyThreadCount == 0);
Assert.Null(scheduler.OldestBusyAge);
}
private static async Task WaitUntilAsync(Func<bool> condition)
{
for (var i = 0; i < 100 && !condition(); i++)
await Task.Delay(50);
Assert.True(condition(), "condition not met within timeout");
}
}