Skip to content

sandboxset: thread-safe sandbox pool (issue #217)#415

Closed
AmiBuch wants to merge 6 commits intoopen-lambda:mainfrom
AmiBuch:main
Closed

sandboxset: thread-safe sandbox pool (issue #217)#415
AmiBuch wants to merge 6 commits intoopen-lambda:mainfrom
AmiBuch:main

Conversation

@AmiBuch
Copy link
Copy Markdown

@AmiBuch AmiBuch commented Feb 19, 2026

sandboxset: Step 1 — thread-safe sandbox pool (issue #217)

Problem

Each LambdaInstance runs a goroutine (~8 KB stack) that sits idle waiting on channels. Ten warm instances = 80+ KB wasted before serving a single request. The goroutine-per-instance model adds unnecessary complexity and memory overhead.

What this PR does

Introduces go/worker/sandboxset as a new, self-contained package that provides a mutex-protected pool of sandboxes for a single Lambda function — no goroutines required.

The pool itself costs ~500 bytes regardless of how many sandboxes it holds.

Sandbox lifecycle:

     [created]
         |
         v
     [paused]  <---+
         |         |
         v         |
     [in-use]  ----+  (Put)
         |
         v
   [destroyed]     (Destroy / Close / error)

Design decisions

  • API modeled after the C process APIGet (create/reuse), Put (return), Destroy (kill), Close (cleanup) — four methods, nothing else
  • One file per methodget.go, put.go, destroy.go, close.go — each method is independently readable
  • api.go is purely declarative — interface, config, and constructor only; 3 exported symbols total
  • No health checks — if a SOCK container is bad, it is completely destroyed; Unpause() failure in Get already handles this with destroy-and-retry
  • Split-lock pattern in Get — the inUse flag is set under the lock, then Unpause runs outside it so a slow container never stalls the whole pool
  • O(1) removal in Destroy — swap-with-tail, no shifting
  • Per-sandbox scratch dirsConfig.ScratchDirs (*common.DirMaker) creates a unique scratch directory per sandbox internally, so Get() is zero-arg
  • Clean dependency directionsandboxset imports sandbox (interfaces only); sandbox does not import sandboxset

Public API

func New(cfg *Config) (SandboxSet, error)

Get() (sandbox.Sandbox, error)
Put(sb sandbox.Sandbox) error
Destroy(sb sandbox.Sandbox, reason string) error
Close() error

What this PR does NOT do

  • LambdaInstance and its goroutines are unchanged — that is Step 2
  • No tests yet — those will be added before this is merged (MockSandbox + unit tests + integration tests)
  • No capacity management (Warm/Shrink), metrics, or stats — those can be added in later PRs

Next steps

  • Step 2: Replace LambdaFunc.instances list + LambdaInstance goroutines with a SandboxSet
  • Step 3: Use SandboxSet as the node abstraction in the zygote tree, replacing individual containers

@AmiBuch AmiBuch closed this Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant