feat(sdk): websocket-based sandbox event subscription across all SDKs#43
feat(sdk): websocket-based sandbox event subscription across all SDKs#43MDzaja wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
All reported issues were addressed across 52 files
Not reviewed (too large): openapi-specs/api.json (~3,502 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
3be69a9 to
19e8b99
Compare
There was a problem hiding this comment.
14 issues found across 51 files
Not reviewed (too large): openapi-specs/api.json (~3,502 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
There was a problem hiding this comment.
2 issues found across 7 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="sdk-typescript/src/utils/EventDispatcher.ts">
<violation number="1" location="sdk-typescript/src/utils/EventDispatcher.ts:352">
P2: A Node process can still hang after an idle disconnect/reconnect cycle: supportsBackgroundUnref stays true for the dispatcher, but the new Socket.IO Manager/engine handles are created with autoUnref off and this early return skips unref setup. Reapply unref setup for each new Manager open, or reset the capability/applied state when replacing the socket.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
c29c53c to
5f03799
Compare
5f03799 to
8dd754c
Compare
Signed-off-by: MDzaja <mirkodzaja0@gmail.com>
…ault to polling Signed-off-by: MDzaja <mirkodzaja0@gmail.com>
… across all SDKs Signed-off-by: MDzaja <mirkodzaja0@gmail.com>
8dd754c to
6d80f4a
Compare
Signed-off-by: MDzaja <mirkodzaja0@gmail.com>
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
You’re at about 93% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
Signed-off-by: MDzaja <mirkodzaja0@gmail.com>
Ports daytonaio/daytona#3987 into the clients repo across all five SDKs (TypeScript, Python, Go, Ruby, Java).
Summary
Sandbox lifecycle waits (
start/stop/delete/resize/ snapshot /pause) now resolve via real-time Socket.IO events instead of pure polling, with polling retained as a safety net. Each SDK gains a sharedEventDispatcher(one Socket.IO connection per client) and anEventSubscriptionManager(per-sandbox fan-out); everySandboxsubscribes lazily and routes state changes through a singleapplyStatepath that wakes any waiters.The result is faster, lower-latency lifecycle operations (state transitions land in hundreds of ms instead of on the poll interval) while remaining fully backward compatible and degrading gracefully when WebSockets are unavailable.
What changed
New (per SDK):
EventDispatcher+EventSubscriptionManager(plus a rawsocketio_clientfor Go/Ruby). Copied from upstream and adapted to each SDK's conventions.Modified (per SDK):
Sandboxnow tracks state via events (applyState/waitForState),Daytona/client constructs and owns the dispatcher, andlist()/get()/create()/fork()wire the subscription manager into eachSandbox.Because the clients repo had diverged from upstream (cursor-based
list(),domain_allow_list, a clients-onlypause(), secrets pagination, git ops), the port was done via careful 3‑way merges rather than a raw patch, preserving all existing clients-only features.Key design
Daytonaclient; sandboxes multiplex through the subscription manager with reference-counted lifetimes.waitForStateresolves on a pushedsandbox.state.updatedevent, and a periodic poll guarantees completion even if an event is missed or WebSockets are down.applyState; construction sets state directly (no waiters yet). No path mutates state without notifying waiters.Robustness & correctness
Sandboxconstructors (they take internal API-client types and are documented "obtain sandboxes viacreate/get/list").create/list/stop/start/waitFor*all still work via polling and never raise.pause()uses events too. The clients-onlypause()was migrated from its polling loop to the shared event-driven waiter.stop()polling fallback hardened.waitUntilStoppednow uses a 404‑safe refresh, so an ephemeral auto-delete sandbox that becomesdestroyedafter stop resolves cleanly under polling instead of throwing./api), so reverse-proxy deployments athttps://host/prefix/apiwork. Standard…/apideployments are byte-identical to before.Observability
The handshake now carries
source+sdkVersionquery params (mirroring the RESTX-Daytona-Source/X-Daytona-SDK-Versionheaders). This lets Daytona measure fleet-wide WebSocket adoption/health server-side — counting Socket.IO connections keyed by SDK and version vs REST activity — with zero client-side telemetry.New dependencies
python-socketio(added topyproject.toml; both lockfiles regenerated)io.socket:socket.io-client:2.1.2google/uuidpromoted from indirect to directsocket.io-client) and Ruby (websocket-client-simple) were already presentSummary by cubic
Adds opt-in real-time sandbox lifecycle updates across all SDKs via Socket.IO (polling remains the default and fallback). Also adds auto-pause interval support in API clients, makes deletion non-blocking by default with an optional wait, and fixes Go SDK secret state updates.
New Features
eventStreamingorDAYTONA_EVENT_STREAMING=trueevent_streamingorDAYTONA_EVENT_STREAMING=trueEventStreamingin config orDAYTONA_EVENT_STREAMING=trueevent_streamingorDAYTONA_EVENT_STREAMING=trueDaytonaConfig.Builder.eventStreaming(true)orDAYTONA_EVENT_STREAMING=trueEventDispatcher(one connection per client) andEventSubscriptionManager(lazy per-sandbox fan-out with TTL; auto-cleanup on client close). Polling remains a safety net.waitoption/overload to block untildestroyed(with optional timeout).pause()uses events; stop fallback is 404-safe.setAutoPauseIntervalendpoint andautoPauseIntervalon create and sandbox models.sourceandsdkVersion. Exposes the sandbox toolbox proxy URL across SDKs.unrefso the connection doesn’t block process exit.Bug Fixes
updateFromAPIResponse.waitForStateacross SDKs.Written for commit 6d3e54d. Summary will update on new commits.