feat: idle-timeout keepalive model with auto-resume - #3
Open
Javey wants to merge 6 commits into
Open
Conversation
Replace absolute ExpiresAt field with computed property derived from LastActiveAt + Timeout. Data-plane requests (any traffic routed through the proxy) now implicitly reset the idle timer via Manager.MarkActivity, eliminating the need for SDK clients to explicitly call /timeout to keep sandboxes alive. Key changes: - Sandbox.ExpiresAt field → ExpiresAt() computed method - Add Sandbox.Timeout and Sandbox.LastActiveAt as sources of truth - Add LabelTimeout Docker label for Rehydrate to recover original TTL - EnforceTimeouts uses idle check (now - LastActiveAt >= Timeout) instead of absolute deadline (now > ExpiresAt) - dispatch.go NewRouter accepts onActivity callback, wired to Manager.MarkActivity in main.go - MarkActivity coalesces writes (default 1s) to avoid lock contention - Config: EDVABE_KEEPALIVE_ENABLED (default on), EDVABE_KEEPALIVE_COALESCE - API responses and dashboard include lastActiveAt field Design inspired by CubeSandbox's traffic-driven keepalive model.
KeepaliveEnabled was a bool with broken default handling — both branches of the if set true, making it impossible to disable keepalive. Changed to *bool: nil = default on, &true = explicit on, &false = off.
Drop *bool three-state approach. main.go is the only Options constructor and always passes a concrete bool. The original bug was just redundant if-branches — a direct assignment fixes it.
Pre-flight ContainerInspect before pause/unpause: Pause returns early if already paused, Unpause returns early if already running. Robust against Docker API message changes across versions. Fixes the Manager TOCTOU race (Resume/Connect check State==Paused under lock, release, then call unpause - a concurrent resume wins the race) and enables recovery from external docker commands.
Data-plane traffic (any request routed through the proxy) now auto-resumes a paused sandbox before forwarding. This mirrors CubeSandbox sandbox_state.lua gate: a browser refresh or SDK request to a paused sandbox transparently unpauses it instead of hanging or erroring. NewProxy gains a third AutoResumer interface param (satisfied by Manager.Connect, which unpauses + resets the idle clock). Running sandboxes skip the check entirely. Paused sandboxes get Connect(id, sb.Timeout) — preserving the original TTL while granting a fresh idle lease. Two new tests: TestAutoResumePausedSandbox verifies the resume+forward path; TestProxyNoResumeForRunningSandbox verifies no spurious Connect for running sandboxes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the absolute
ExpiresAtdeadline model with a computedLastActiveAt + Timeoutidle model, adds data-plane auto-keepalive, idempotent docker pause/unpause, and proxy-level auto-resume for paused sandboxes.Changes
1. Idle-timeout model with data-plane auto-keepalive
Sandbox.ExpiresAtfield → computedExpiresAt()method (LastActiveAt + Timeout)LastActiveAt+Timeoutfields as sources of truthManager.MarkActivity(id)called by dispatch on every data-plane request (coalesced to 1s/sandbox)EnforceTimeoutsuses idle check (now - LastActiveAt >= Timeout) instead of absolute deadlineLabelTimeoutDocker label for Rehydrate to recover original TTLEDVABE_KEEPALIVE_ENABLED(default on),EDVABE_KEEPALIVE_COALESCE(default 1s)lastActiveAtfield2. Idempotent docker pause/unpause
ContainerInspectbefore pause/unpause: return nil if already in desired state3. Auto-resume paused sandboxes on data-plane requests
Manager.Connect(id, sb.Timeout)to resume + reset idle clockInspired by CubeSandbox's traffic-driven keepalive model and sandbox_state.lua auto-resume gate.
Test plan
go vet ./...passesgo test ./...passesTestAutoResumePausedSandbox— verifies resume+forward pathTestProxyNoResumeForRunningSandbox— verifies no spurious Connect for running sandboxesExpiresAt()method