Skip to content

fix(sdk): reject negative readiness polling interval in Python and JavaScript - #1826

Merged
Pangjiping merged 2 commits into
opensandbox-group:mainfrom
Dev-next-gen:fix/python-sdk-negative-polling-interval
Sep 14, 2026
Merged

Pangjiping merged 2 commits into
opensandbox-group:mainfrom
Dev-next-gen:fix/python-sdk-negative-polling-interval

Conversation

@Dev-next-gen

@Dev-next-gen Dev-next-gen commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

I noticed that the Kotlin SDK now rejects a non-positive ready polling interval (f494483) because a no-op sleep turns the health check into a spin, and went looking at the Python SDK. ReadinessBudget hands health_check_polling_interval straight to the sleep call, with no check.

With a negative interval the two Python flavours fail differently:

  • async: asyncio.sleep() returns immediately for a negative delay, so create / connect / resume / check_ready poll /ping in a tight loop until the deadline. Against a mock transport answering 503, a one-second Sandbox.connect sent 5 pings with the default 200 ms interval and about 3,500 with timedelta(milliseconds=-1).
  • sync: time.sleep() raises ValueError, which comes out as SandboxInternalException: Failed to resume sandbox: sleep length must be non-negative. For SandboxSync.create that happens after the sandbox has been provisioned, so it gets killed again because of a client-side argument.

This change raises InvalidArgumentException for a negative interval in ReadinessBudget, and checks it before any request in create (only when the health check is not skipped, since the interval is unused otherwise) and in resume (which calls the resume API before building the budget). connect and check_ready are covered by the budget itself, before any request.

After review I applied the same check to the JavaScript SDK, which passed healthCheckPollingInterval straight to setTimeout. Node clamps a negative delay to about 1 ms, so a one-second Sandbox.connect against a health check returning false made 67 attempts with -1. create (when the health check is not skipped), connect, resume and waitUntilReady now throw InvalidArgumentException before any request. The JS pool options already rejected negative values.

I deliberately left a zero interval allowed: the existing tests call check_ready(..., polling_interval=timedelta(seconds=0)), so I only reject values that never worked in sync mode.

Testing

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

New tests/test_readiness_polling_interval.py (16 cases, async and sync, create/connect/resume, asserting no HTTP request is sent). All 14 rejection cases fail on main and pass with the change; the full Python SDK suite passes (625 tests), and ruff check and pyright on the touched files are clean.

New tests/sandbox.polling-interval.test.mjs (create/connect/resume rejections plus a skipped health check case). The three rejection cases fail on main (health check timeout after 67 attempts) and pass with the change. I couldn't run pnpm install on my machine, so I ran the JS tests from the TypeScript sources with Node's type stripping and a stub for openapi-fetch: the new file plus the create, connect/resume, endpoint-readiness and pool suites give 71 passing tests. ESLint was not run locally.

Breaking Changes

  • None
  • Yes (describe impact and migration path)

A negative interval already crashed the sync SDK; in async it only produced a busy loop. Zero and positive intervals behave as before.

Checklist

  • Linked Issue or clearly described motivation
  • Added/updated docs (if needed)
  • Added/updated tests (if needed)
  • Security impact considered
  • Backward compatibility considered

AI tools used

ReadinessBudget passed the polling interval straight to the sleep call.
With a negative interval the async SDK's asyncio.sleep() returns
immediately, so create/connect/resume/check_ready poll the health
endpoint in a tight loop until the deadline (about 3,500 pings in a
one-second budget against a mock transport, versus 5 with the default
200 ms). The sync SDK's time.sleep() raises ValueError instead, which
surfaces as SandboxInternalException("... sleep length must be
non-negative") after create has already provisioned and killed the
sandbox.

Reject negative intervals with InvalidArgumentException in
ReadinessBudget, and validate before any request in create (when the
health check is not skipped) and resume. A zero interval stays allowed,
since existing tests rely on it.
@github-actions github-actions Bot added sdk/python size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Sep 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: 0f17d41e21

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

The JavaScript SDK passed healthCheckPollingInterval straight to
setTimeout, which runs a negative delay after about 1 ms. A one-second
Sandbox.connect against a health check that keeps returning false made
67 attempts with an interval of -1.

Reject negative intervals with InvalidArgumentException before any
request in create (when the health check is not skipped), connect,
resume and waitUntilReady, matching the Python SDK change. Zero stays
allowed, and pool options already reject negative values.
@Dev-next-gen Dev-next-gen changed the title fix(python-sdk): reject negative readiness polling interval fix(sdk): reject negative readiness polling interval in Python and JavaScript Sep 12, 2026

@Pangjiping Pangjiping left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@Pangjiping
Pangjiping merged commit d11f6c5 into opensandbox-group:main Sep 14, 2026
56 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sdk/js sdk/python size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants