Repository navigation
Add warm-sandbox-pool example - #3
Conversation
Demonstrates maintaining a pool of pre-initialized warm sandboxes for Ruby-based applications, eliminating startup delays by late-binding conversations to prepared sandboxes. Features: - Pre-initialized sandboxes with Ruby/Sinatra already running - Automatic pool refill when sandboxes are consumed - Web UI for monitoring pool status and starting conversations - Alternative to custom images using OpenHands Cloud APIs Recovered from conversation 4c1947abfc4f4ed6ba76d9b4c7324d8f Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Found by running the recipe end to end against a live OpenHands instance. Broken as written: - Init script upload used a non-existent agent-server endpoint (/api/upload-files); use /api/file/upload?path=... - Init script ran apt-get/gem as the non-root sandbox user; use sudo - Current Sinatra needs rackup and puma to boot Resource safety: - Delete a sandbox as soon as provisioning fails - Stop refilling after MAX_FAILURES consecutive failures (was unbounded) - Delete unused pool sandboxes on shutdown (SIGTERM/Ctrl-C) - Bind the UI to 127.0.0.1 by default and drop the open CORS config Other fixes: - Upload quote_service.rb instead of a divergent copy embedded in the script - UI conversation link pointed at localhost instead of OpenHands - Add INIT_TIMEOUT, MAX_FAILURES, HOST settings that the docs described - README/QUICKSTART: correct Ruby install method, service access, timings, troubleshooting commands and parameter docs - test_structure.py also syntax-checks the init script and controller Co-authored-by: openhands <openhands@all-hands.dev>
Docs preview✅ Docs preview is ready: https://allhandsai-cookbook-preview-pr-3.mintlify.site Docs PR: OpenHands/docs#911 (draft preview; never merged, closes with this PR). |
…claims Live view (extends the existing page, no new toolchain): - Controller records an event feed: sandbox created, preparing, ready, pulled from the pool, claimed, failed, deleted, miss, halted, shutdown - Stats strip: claims, average warm-up, average attach time - "Claimed by conversations" list with per-sandbox warm-up, time waited in the pool, attach time and a link to the conversation - Activity feed panel; the conversation form no longer hides itself when the pool is momentarily empty, it shows a refilling notice and disables Start Fixes found while testing it: - A sandbox pulled from the pool whose conversation failed to attach was stranded as ALLOCATED and never deleted; it is now deleted Docs accuracy: measured a cold conversation start (12-26s, before any Ruby install) against attaching to a warm sandbox (~10-12s). The pool removes sandbox boot + init script from the wait, not the conversation start itself. Replaced "instant"/"no delay" wording and added a table of what to expect. Co-authored-by: openhands <openhands@all-hands.dev>
…merge) Preview of the Enterprise Cookbook pages produced by OpenHands/enterprise-cookbook#3 (Add warm-sandbox-pool example), rendered from OpenHands/enterprise-cookbook@ec179f1. **Do not merge.** This draft exists only to get a Mintlify preview. It is updated on every push to the source PR and closed when that PR closes. Merged changes reach the docs through a separate `cookbook-sync` PR. _Opened automatically by the docs-preview workflow in OpenHands/enterprise-cookbook._
Explain how an agent can run the example on a sandbox work port (HOST=0.0.0.0 PORT=12000), hand the user the work URL to watch the live UI, and stop the controller afterwards. Verified through a real work URL: the page, the SSE stream (frames arrive every ~2s, unbuffered) and POST /api/conversation/start all work via the proxy. The UI has no login, so the docs carry an explicit security note: anyone with the URL can start a conversation with an arbitrary prompt on the user's account. Acceptable for a brief demo with an unguessable URL; not for anything long-lived. Co-authored-by: openhands <openhands@all-hands.dev>
…merge) Preview of the Enterprise Cookbook pages produced by OpenHands/enterprise-cookbook#3 (Add warm-sandbox-pool example), rendered from OpenHands/enterprise-cookbook@ecb63c5. **Do not merge.** This draft exists only to get a Mintlify preview. It is updated on every push to the source PR and closed when that PR closes. Merged changes reach the docs through a separate `cookbook-sync` PR. _Opened automatically by the docs-preview workflow in OpenHands/enterprise-cookbook._
…progress
Access code
- The controller generates a random 10-character code at startup (no look-alike
characters), prints it in its output, and the browser signs in by pasting it.
- Everything except the sign-in page and its static assets returns 401 without
the session cookie: the dashboard, the status API, the SSE stream and
POST /api/conversation/start. Comparison is constant-time; the code and the
session key live only in memory, so a restart invalidates both. An open page
notices the 401 and falls back to the sign-in page.
- Docs: the sandbox work-URL section now tells the agent to read the code from
the controller's output and hand the user the link and the code, and the
security note describes what the code does and does not protect.
Refill visibility
- New line under the stats: "Refilling: N in progress (R ready, target T)", or
an explanation of why nothing is happening ("2 of 3 ready. A refill starts
when ready drops below 2.").
- The feed now records why a refill started: "1 ready is below the threshold
of 2: starting 2 sandbox(es) to get back to 3".
- The claim success box no longer says the pool refills immediately, which was
not true when ready is still at the threshold.
Verified on beta through a real work URL: unauthenticated requests get 401
(including trailing-slash and double-slash variants), a wrong code gets 403,
a lowercase correct code signs in, claims work through the session, and a
controller restart sends an open page back to sign-in. Test sandboxes and
conversations were deleted.
Co-authored-by: openhands <openhands@all-hands.dev>
…merge) Preview of the Enterprise Cookbook pages produced by OpenHands/enterprise-cookbook#3 (Add warm-sandbox-pool example), rendered from OpenHands/enterprise-cookbook@85f5a66. **Do not merge.** This draft exists only to get a Mintlify preview. It is updated on every push to the source PR and closed when that PR closes. Merged changes reach the docs through a separate `cookbook-sync` PR. _Opened automatically by the docs-preview workflow in OpenHands/enterprise-cookbook._
…l size in the agent steps Styling - Restyle the UI with the OpenHands Agent Canvas "DeepSea" dark theme tokens (cool-grey scale on #0B0E14, warm gold primary with dark button text, the host's success and danger colors), flat 1px borders, no gradients or lift animations. Header uses the OpenHands logo and favicon from OpenHands/OpenHands. - Status badges, info/result boxes and inputs use translucent tints so they stay readable on the dark surfaces. Port - Default PORT is now 12000, the first port an OpenHands sandbox publishes as a work URL, so running from a sandbox needs only HOST=0.0.0.0 and local runs use the same number. Agent instructions - The sandbox steps now say to use the default pool settings (pool of 3, threshold 2). The earlier advice to try POOL_SIZE=1 POOL_THRESHOLD=1 first leaves nothing to watch, because a refill only starts once ready drops below the threshold; removed from README and QUICKSTART. Verified on beta through a work URL with the exact documented command (HOST=0.0.0.0, defaults): sign-in, dashboard, two claims, refill and the activity feed all render correctly in the new theme. Co-authored-by: openhands <openhands@all-hands.dev>
…merge) Preview of the Enterprise Cookbook pages produced by OpenHands/enterprise-cookbook#3 (Add warm-sandbox-pool example), rendered from OpenHands/enterprise-cookbook@154dc5d. **Do not merge.** This draft exists only to get a Mintlify preview. It is updated on every push to the source PR and closed when that PR closes. Merged changes reach the docs through a separate `cookbook-sync` PR. _Opened automatically by the docs-preview workflow in OpenHands/enterprise-cookbook._
The message box is now prefilled in the HTML and no longer cleared after a claim, so each press of Start Conversation sends the example without retyping. The grey placeholder only shows if the user empties the box. Verified on beta: two claims in a row, no typing between them. Co-authored-by: openhands <openhands@all-hands.dev>
…merge) Preview of the Enterprise Cookbook pages produced by OpenHands/enterprise-cookbook#3 (Add warm-sandbox-pool example), rendered from OpenHands/enterprise-cookbook@41d33bb. **Do not merge.** This draft exists only to get a Mintlify preview. It is updated on every push to the source PR and closed when that PR closes. Merged changes reach the docs through a separate `cookbook-sync` PR. _Opened automatically by the docs-preview workflow in OpenHands/enterprise-cookbook._
There was a problem hiding this comment.
Taste: Good - Well-executed cookbook example with thorough documentation and proper validation.
Summary
This PR adds a comprehensive example demonstrating the "warm sandbox pool" pattern for eliminating sandbox startup delays. The implementation is clean, well-documented, and includes proper security controls.
Strengths
- Complete documentation: Both README.md and QUICKSTART.md are thorough and well-structured
- Security controls: Proper access code implementation using constant-time comparison, session-based auth with HTTPOnly cookies, and XSS protection via escapeHtml
- Resource management: Automatic cleanup of unused sandboxes on shutdown, proper thread synchronization with locks
- Error handling: Comprehensive error handling with circuit breaker pattern (MAX_FAILURES), proper timeout handling, and graceful degradation
- Validation: Includes test_structure.py for structural validation
- Production-ready patterns: Demonstrates real-world techniques applicable beyond the demo
Validation Evidence
Per the PR description, this has been validated with:
- Full run on beta OpenHands instance (pool fills to 3, consecutive claims work, refill triggers correctly)
- Run from OpenHands sandbox through work URL (all routes work through proxy with access code)
- Cleanup verified (unused pool sandboxes deleted on shutdown)
- Static checks pass (ruff, pyright, test_structure.py)
- CI green
Architecture Review
The implementation correctly:
- Uses threading with proper locking for concurrent sandbox provisioning
- Implements SSE for real-time UI updates
- Handles the full lifecycle: provision → initialize → pool → claim → attach
- Includes circuit breaker to halt refilling after repeated failures
- Provides detailed activity logging for debugging
The Ruby service binding to 0.0.0.0 inside the sandbox is correct - it runs in an isolated container and needs to be accessible to the agent.
Repository Fit
This is an excellent addition to the enterprise cookbook:
- Demonstrates an advanced but practical pattern
- Well-suited for the examples repository structure
- Provides clear value for organizations needing fast conversation startup
- Includes both simple demo (Ruby quotes service) and extensible architecture
[RISK ASSESSMENT]: LOW. All additions to a new subdirectory with self-contained example code. No changes to existing examples or shared infrastructure. Validated working implementation with comprehensive testing.
Verdict: ✅ APPROVE - No material issues found. This is a well-designed, thoroughly documented, and properly validated addition to the cookbook.
Was this automated review useful? React with 👍 or 👎 to this review to help us measure review quality.
Workflow run: https://github.com/OpenHands/enterprise-cookbook/actions/runs/37679823832
Demonstrates maintaining a pool of pre-initialized warm sandboxes, eliminating startup delays by late-binding conversations to prepared sandboxes.
Features:
HOST=0.0.0.0to give you a link and the codeValidation
test_structure.pypass, and CI is green.Recovered from conversation 4c1947abfc4f4ed6ba76d9b4c7324d8f