Skip to content

fix(placement,fc): memory-aware sandbox placement and DeflateOnOom - #3380

Open
AdaAibaby wants to merge 1 commit into
e2b-dev:mainfrom
AdaAibaby:fix/memory-aware-placement-oom-resilience
Open

fix(placement,fc): memory-aware sandbox placement and DeflateOnOom#3380
AdaAibaby wants to merge 1 commit into
e2b-dev:mainfrom
AdaAibaby:fix/memory-aware-placement-oom-resilience

Conversation

@AdaAibaby

@AdaAibaby AdaAibaby commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements all improvements from #3379. Three gaps in memory management are addressed:

1. Memory-aware placement filter (BestOfKMaxMemoryOvercommit feature flag)

The BestOfK scheduler was purely CPU-aware — nodes were never filtered or scored on memory, creating a path to host OOM. This adds a hard memory filter in sample() controlled by a new LaunchDarkly flag:

best-of-k-max-memory-overcommit   default: 0 (disabled, current behaviour)
                                  100 = 1.0× (no overcommit)
                                  150 = 1.5× overcommit

A node is excluded from placement when:

MemoryAllocatedBytes + requested_bytes > M × MemoryTotalBytes

Safety guards:

  • M = 0 → filter is off (backward-compatible default)
  • MemoryTotalBytes = 0 (node hasn't checked in yet) → filter is skipped
  • Deployed by setting the flag to a non-zero value in LaunchDarkly; no restart required

2. Balloon DeflateOnOom = true

The virtio-balloon was configured with DeflateOnOom = false. When free-page hinting reclaimed idle pages from the guest and the guest later needed that memory, the balloon would not deflate — causing avoidable in-guest OOM kills. Setting DeflateOnOom = true allows Firecracker to return those pages to the guest on demand. The Firecracker MemSizeMib hard ceiling is unchanged.

3. Test infrastructure

  • 6 new placement tests covering: filter disabled, full node excluded, headroom allowed, overcommit ratio, unreported total memory, tiebreak between tight/spacious nodes
  • WithTotalMemoryBytes(bytes uint64) test helper added to the node mock

Files changed

File Change
packages/orchestrator/pkg/sandbox/fc/client.go deflateOnOom = true
packages/shared/pkg/featureflags/flags.go new BestOfKMaxMemoryOvercommit flag
packages/api/internal/orchestrator/placement/placement_best_of_K.go M float64 in config, memory filter in sample()
packages/api/internal/orchestrator/orchestrator.go read flag, pass M to config
packages/api/internal/orchestrator/nodemanager/mock.go WithTotalMemoryBytes test option
packages/api/internal/orchestrator/placement/placement_memory_filter_test.go 6 new tests
packages/api/internal/orchestrator/placement/placement_best_of_K_test.go updated sample() call sites

Rollout

  1. Merge this PR (no behaviour change — M defaults to 0)
  2. Monitor MemoryAllocatedBytes / MemoryTotalBytes per node in existing dashboards
  3. Enable filter by setting best-of-k-max-memory-overcommit = 100 in LaunchDarkly

/cc @jakubno @dobrac @ValentaTomas @arkamar @tvi Looking forward to your code review.

Closes e2b-dev#3379.

Three improvements to prevent host OOM and reduce avoidable in-guest OOM
kills when sandboxes approach their Firecracker MemSizeMib limit.

1. Memory hard filter in BestOfK placement
   Add BestOfKConfig.M (memory overcommit ratio) populated from the new
   best-of-k-max-memory-overcommit feature flag (default 0 = disabled).
   When M > 0, sample() skips nodes where
     MemoryAllocatedBytes + requested > M × MemoryTotalBytes
   so sandboxes are never scheduled onto hosts without available memory.
   The filter is a no-op when M=0 (current behaviour) or when a node
   has not yet reported MemoryTotalBytes, preserving backward compat.

2. balloon DeflateOnOom = true
   The virtio-balloon was configured with DeflateOnOom=false, meaning
   pages returned to the host via free-page hinting were not given back
   to the guest when it approached its memory ceiling. Setting it to
   true allows Firecracker to deflate the balloon on demand, reducing
   avoidable in-guest OOM kills without changing the hard MemSizeMib
   ceiling enforced by the VMM.

3. Tests and helpers
   - 6 new table-driven tests cover all branches of the memory filter
     (disabled, full node, headroom, overcommit, unknown total, tiebreak)
   - WithTotalMemoryBytes TestOption added to the node mock so tests can
     express realistic memory scenarios without reaching into internals
@cla-bot cla-bot Bot added the cla-signed label Jul 24, 2026
@ValentaTomas
ValentaTomas force-pushed the main branch 2 times, most recently from 5aad415 to d71980e Compare July 25, 2026 22:53
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.

2 participants