Skip to content

perf(sdks): release idle sandboxes with bounded concurrency - #1475

Merged
Pangjiping merged 4 commits into
opensandbox-group:mainfrom
jianpingpei:fix/sdk-pool-release-concurrency
Aug 13, 2026
Merged

Pangjiping merged 4 commits into
opensandbox-group:mainfrom
jianpingpei:fix/sdk-pool-release-concurrency

Conversation

@jianpingpei

@jianpingpei jianpingpei commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Closes #1472.

  • Replace serial idle-sandbox deletion in the Kotlin and Python pools with bounded concurrency of 50.
  • Replace the Go pool's unbounded fire-and-forget goroutines with a bounded worker pool that waits for cleanup to finish.
  • Preserve best-effort per-sandbox failure handling and continue killing IDs already removed from the state store when a later drain operation fails.
  • Keep the concurrency limit internal, with no public API or configuration changes.

Testing

  • Not run (explain why)
  • Unit tests
  • Integration tests
  • e2e / manual verification

Automated checks:

  • cd sdks/sandbox/go && go test ./...
  • cd sdks/sandbox/python && uv run ruff check src/opensandbox/pool_async.py src/opensandbox/sync/pool.py tests/test_pool_async.py tests/test_pool_sync.py
  • cd sdks/sandbox/python && uv run pyright src/opensandbox/pool_async.py src/opensandbox/sync/pool.py
  • cd sdks/sandbox/python && uv run pytest tests/test_pool_async.py tests/test_pool_sync.py -q
  • cd sdks/sandbox/kotlin && ./gradlew spotlessCheck :sandbox:test --tests '*releaseAllIdle*'
Version Warmup release_all_idle() Released Remote remaining
Before (c3e97bfb) 12.016s 8.349s 100 0
After (a6e42483) 12.024s 0.774s 100 0

The release path was approximately 10.8x faster (90.7% lower elapsed time).

Breaking Changes

  • None
  • Yes (describe impact and migration path)

Checklist

  • Linked Issue or clearly described motivation
  • Added/updated docs (if needed) — no public API or configuration changes
  • Added/updated tests (if needed)
  • Security impact considered — no authentication, authorization, or protocol changes
  • Backward compatibility considered — existing method signatures and best-effort cleanup semantics are preserved

@github-actions github-actions Bot added sdk/go sdk/java sdk/python sdks size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Aug 12, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a6e424830f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread sdks/sandbox/python/src/opensandbox/pool_async.py
@Pangjiping

Copy link
Copy Markdown
Collaborator

Suggestion: keep the existing release_all_idle() implementations untouched and add a separate parallel variant

Rather than modifying the existing methods in place, I suggest preserving the original implementations and adding new methods that accept a concurrency parameter:

  • Go: keep ReleaseAllIdle(ctx) as-is (existing fire-and-forget behavior); add ReleaseAllIdleParallel(ctx, maxWorkers int). Avoid adding it to the SandboxPool interface to not break existing implementors; document that the new method blocks until all kills complete.
  • Kotlin: keep releaseAllIdle() unchanged; add an overload releaseAllIdle(concurrency: Int = 50).
  • Python (async + sync): keep release_all_idle() unchanged; add release_all_idle_parallel(max_workers: int = 50) (asyncio.Semaphore / ThreadPoolExecutor(min(max_workers, n))).
  • Default value unified at 50 across all three SDKs, with input validation.

Rationale: although this PR does not change any signatures, it changes observable behavior of existing callers (returning immediately vs. blocking until all kills complete, and delayed error propagation on drain failure). A separate parallel method keeps legacy callers byte-for-byte on their old behavior, lets new callers opt in to the ~10.8x speedup explicitly, and is the safest path for SDK backward compatibility. The trade-off is that existing callers must opt in to the parallel variant to get the performance fix — worth noting in the PR description/docs.

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Aug 12, 2026
@jianpingpei

Copy link
Copy Markdown
Contributor Author

Addressed in 992100d. The legacy methods are restored unchanged, and bounded parallel cleanup is now opt-in:

  • Go keeps ReleaseAllIdle(ctx) fire-and-forget and adds concrete-only ReleaseAllIdleParallel(ctx, maxWorkers); it is not added to the interface.
  • Kotlin keeps serial releaseAllIdle() and adds releaseAllIdle(concurrency).
  • Python sync/async keep serial release_all_idle() and add release_all_idle_parallel(max_workers=50).
  • All parallel entry points validate positive concurrency, block until every drained ID has received a best-effort kill attempt, and the docs now call out the behavioral difference.

For Kotlin, the concurrency argument is intentionally explicit: a defaulted overload next to the preserved no-arg overload would be unreachable for no-arg calls, which must continue selecting the legacy serial method.

I also reran the same pre-production benchmark with 100 idle sandboxes and concurrency 50. The legacy serial Python path took 11.422s; the new parallel path took 0.749s (~15.25x faster). Both runs ended with store idle=0, remote remaining=0, and the test pools destroyed.

Comment thread sdks/sandbox/go/pool.go
Comment thread sdks/sandbox/go/pool_test.go
@Pangjiping
Pangjiping merged commit e926123 into opensandbox-group:main Aug 13, 2026
54 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation sdk/go sdk/java sdk/python sdks size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(sdks): releaseAllIdle kills idle sandboxes serially (500 sandboxes ≈ 8 min)

2 participants