Skip to content

feat(api/placement): classify capacity-shortage reason for logs and traces - #3822

Open
AdaAibaby wants to merge 1 commit into
e2b-dev:mainfrom
AdaAibaby:feat/placement-capacity-shortage-reason
Open

AdaAibaby wants to merge 1 commit into
e2b-dev:mainfrom
AdaAibaby:feat/placement-capacity-shortage-reason

Conversation

@AdaAibaby

@AdaAibaby AdaAibaby commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #3821. The capacity_unavailable 503 ("not enough capacity …") never says which capacity was short — hugepage memory pool, node ResourceExhausted refusals, or an empty candidate set. The placement loop already knows (poolsFull, refusals, per-node status) but discards it at the return sites.

This adds a CapacityShortageReason and diagnostic fields to NoNodesAvailableError, populated at every return site (the loop deadline, the answered/allExcluded paths, and the BestOfK.chooseNode full-pool return), and records them on the place-sandbox span plus one structured warn log.

field meaning
Reason hugepage_pool_full | node_refusals | no_candidate_node
Attempts completed create attempts before giving up
Refusals ResourceExhausted refusals across nodes
PoolsFull at least one sampled node failed memory admission
LastRefusal classified label of the last node refusal

classifyRefusal maps the node's ResourceExhausted wording (running_cap / starting_cap / guest_memory_stopping / node_not_accepting / lifecycle_busy) so a memory-pool shortage is distinguishable from a running-count cap at a glance.

Not a behaviour change

  • Error() still returns "no nodes available"; the client-facing 503 message and error_code are unchanged.
  • The zero value of NoNodesAvailableError behaves exactly as before, so every existing errors.As match keeps working.
  • No proto / OpenAPI / wire change — diagnostics are server-side only.

Test

TestPlaceSandbox_EveryPoolFull_ReasonIsHugepagePool asserts the classified reason on the pool-full path. go build ./..., go vet, and the full internal/orchestrator/placement suite pass. (The evictor package's Redis-backed tests need a test Redis and are unrelated.)

/cc @ryan-sana Looking forward to your code review.

…races

The "Failed to place sandbox: not enough capacity" error (503,
capacity_unavailable) is returned whenever placement finds no node with
room, but it never says which capacity was short: the hugepage memory
pool (MemoryAdmission), node-side ResourceExhausted refusals (running
cap, starting cap, a guest still stopping, node not accepting), or an
empty candidate set. Operators cannot tell a memory shortage from a
running-count cap without guessing.

Add a CapacityShortageReason and diagnostic fields (Attempts, Refusals,
PoolsFull, LastRefusal) to NoNodesAvailableError, populated at every
return site and recorded on the place-sandbox span plus a structured
warn log. classifyRefusal labels the node ResourceExhausted message so
the last refusal reason is carried too.

The client-facing message is unchanged (still "no nodes available" /
the 503 text), and the zero value keeps the original behaviour, so no
wire or API change. Diagnostics are server-side only.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Placement "not enough capacity" error does not say which capacity was short (hugepage pool vs node refusals)

2 participants