Problem
When the orchestrator returns a ResourceExhausted gRPC error, the API logs it as:
WARN Node exhausted, trying another node {sandboxId: ..., nodeId: ..., error: ...}
However the error field only carries a generic message with no actionable numbers, making it hard to tell from logs why placement was rejected. There are three ResourceExhausted sites:
1. Max running sandboxes (sandboxes.go)
runningSandboxes := s.sandboxFactory.Sandboxes.Count()
if runningSandboxes >= maxRunningSandboxesPerNode {
return nil, status.Errorf(codes.ResourceExhausted,
"max number of running sandboxes on node reached (%d), please retry",
maxRunningSandboxesPerNode) // ← max only, current omitted
}
runningSandboxes is right there in scope but isn't included in the error.
2. Too many sandboxes starting (sandboxes.go — TryAcquire branch)
acquired := s.startingSandboxes.TryAcquire(1)
if !acquired {
return nil, status.Errorf(codes.ResourceExhausted,
"too many sandboxes starting on this node, please retry") // ← no counts at all
}
3. Too many sandboxes resuming (utils.go — Acquire / resume branch)
err := s.startingSandboxes.Acquire(ctx, 1)
if err != nil {
return status.Errorf(codes.ResourceExhausted,
"too many sandboxes resuming on this node, please retry") // ← no counts at all
}
Impact
Without current/max values in the error, the "Node exhausted" log line carries no information about how exhausted the node is, making it impossible to distinguish between:
- A node that is truly at capacity (e.g.
current=50, max=50)
- A node that hit the semaphore limit for in-flight starts (e.g.
current=10, max=10) while many slots remain
This matters during placement: the API retries across nodes when it sees ResourceExhausted, and there is no structured signal to tell whether the whole fleet is saturated or just a subset of nodes.
Fix
- Add
Current() int64 and Limit() int64 methods to AdjustableSemaphore in packages/shared/pkg/utils/resizable_semaphore.go
- Update all three
ResourceExhausted error messages to include current=N, max=M
Example after fix:
"max number of running sandboxes on node reached: current=50, max=50, please retry"
"too many sandboxes starting on this node: current=10, max=10, please retry"
"too many sandboxes resuming on this node: current=10, max=10, please retry"
Problem
When the orchestrator returns a
ResourceExhaustedgRPC error, the API logs it as:However the
errorfield only carries a generic message with no actionable numbers, making it hard to tell from logs why placement was rejected. There are threeResourceExhaustedsites:1. Max running sandboxes (
sandboxes.go)runningSandboxesis right there in scope but isn't included in the error.2. Too many sandboxes starting (
sandboxes.go—TryAcquirebranch)3. Too many sandboxes resuming (
utils.go—Acquire/ resume branch)Impact
Without current/max values in the error, the "Node exhausted" log line carries no information about how exhausted the node is, making it impossible to distinguish between:
current=50, max=50)current=10, max=10) while many slots remainThis matters during placement: the API retries across nodes when it sees
ResourceExhausted, and there is no structured signal to tell whether the whole fleet is saturated or just a subset of nodes.Fix
Current() int64andLimit() int64methods toAdjustableSemaphoreinpackages/shared/pkg/utils/resizable_semaphore.goResourceExhaustederror messages to includecurrent=N, max=MExample after fix: