feat(worker-mcp): raise wait_for_task_change timeout, expose queue slot state
MaxTimeoutSeconds was 170s against runs that take tens of minutes, forcing a dozen full-context wait rounds per long-running batch. Raise it to 900s and raise MCP_TOOL_TIMEOUT in lockstep (ClaudeProcess + every InteractiveLaunchSpecService launch spec) to 930000ms so the client connection actually stays open that long instead of aborting first. Add get_queue_state (QueueStateMcpTools): configured vs. effective parallel-slot count (via QueueService.GetSlotCountsAsync, extracted from the former GetEffectiveMaxParallelAsync), active slots with taskId + startedAt including the run_task_now override slot, and queued tasks in pick order -- so a caller can observe queue occupancy instead of inferring it from maxParallelExecutions.
This commit is contained in:
@@ -125,7 +125,7 @@ public sealed class QueueService : BackgroundService
|
||||
|
||||
await Task.WhenAny(wakeTask, timerTask);
|
||||
|
||||
var maxParallel = await GetEffectiveMaxParallelAsync(stoppingToken);
|
||||
var (_, maxParallel) = await GetSlotCountsAsync(stoppingToken);
|
||||
|
||||
var gateDecision = await _usageGate.EvaluateAsync(stoppingToken);
|
||||
await ReportUsageGateTransitionAsync(gateDecision);
|
||||
@@ -200,11 +200,13 @@ public sealed class QueueService : BackgroundService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configured parallelism, stepped down by <see cref="UsageThrottle"/> ahead of the hard usage
|
||||
/// gate. A missing snapshot (poll hasn't landed / endpoint unreachable) fails open to the
|
||||
/// configured value — a broken usage poll must never stall the queue.
|
||||
/// Configured parallelism, and that same value stepped down by <see cref="UsageThrottle"/>
|
||||
/// ahead of the hard usage gate. A missing snapshot (poll hasn't landed / endpoint
|
||||
/// unreachable) fails open to the configured value — a broken usage poll must never stall
|
||||
/// the queue. Also called by <c>get_queue_state</c> (External MCP) to surface the throttle
|
||||
/// from outside the process.
|
||||
/// </summary>
|
||||
private async Task<int> GetEffectiveMaxParallelAsync(CancellationToken ct)
|
||||
public async Task<(int Configured, int Effective)> GetSlotCountsAsync(CancellationToken ct)
|
||||
{
|
||||
int configured;
|
||||
int softPct, hardPct, gateFivePct, gateSevenPct;
|
||||
@@ -221,14 +223,14 @@ public sealed class QueueService : BackgroundService
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to read max parallel executions; defaulting to 1");
|
||||
return 1;
|
||||
return (1, 1);
|
||||
}
|
||||
|
||||
var snapshot = _usageState.Snapshot;
|
||||
if (snapshot is null || _usageState.LastError is not null)
|
||||
{
|
||||
_lastEffectiveSlots = configured;
|
||||
return configured;
|
||||
return (configured, configured);
|
||||
}
|
||||
|
||||
var effective = UsageThrottle.EffectiveSlots(
|
||||
@@ -236,7 +238,7 @@ public sealed class QueueService : BackgroundService
|
||||
softPct, hardPct, gateFivePct, gateSevenPct);
|
||||
|
||||
ReportThrottleTransition(configured, effective, snapshot);
|
||||
return effective;
|
||||
return (configured, effective);
|
||||
}
|
||||
|
||||
private void ReportThrottleTransition(int configured, int effective, UsageSnapshot snapshot)
|
||||
|
||||
Reference in New Issue
Block a user