Conversation
…tion Prevent accumulation of stale SandboxClaims, Sandboxes, and PodFailed pods: 1. Configure lifecycle shutdownPolicy: Delete and ttlSecondsAfterFinished on SandboxClaims upon creation, ensuring automatic Kubernetes controller GC even if client processes fail or terminate abruptly. 2. Defensively clean up Sandbox and SandboxClaim custom resources on SWEEnv.close(), including terminate calls and Kubernetes CRD deletion even when the underlying env.close() raises an exception. 3. Add context manager (__enter__, __exit__) and destructor (__del__) to SWEEnv to ensure sandboxes are always released back to the fleet or deleted. 4. In TrajectoryCollectEngine, wrap the entire episode lifecycle (reset, rollout loop, and reward computation) in try ... finally: await self._close() to guarantee environment cleanup on exceptions during reset or rollout steps. 5. In template.py, validate and normalize CPU and memory requests against limits (requests <= limits) and add activeDeadlineSeconds to prevent admission ReconcilerErrors and indefinitely running leaked pods.
andytwigg
requested review from
abheesht17,
hgao327,
jiangyangmu,
lc5211,
s-noghabi,
sizhit2,
tianshub and
wang2yn84
as code owners
September 19, 2026 08:11
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
This PR resolves an issue where sandboxes from failed, completed, or cancelled trajectories accumulate in Kubernetes clusters as stale
SandboxClaim/SandboxCRDs andPodFailed/ restart-looping pods.Root Causes
shutdownPolicy: Retaindefault):When
SandboxClaimcustom resources were created by the agent-sandbox runtime, they defaulted toshutdownPolicy: RetainwithoutttlSecondsAfterFinished. When backing pods completed or terminated with exit code 137 (PodFailed), the Kubernetesagent-sandboxcontroller kept the claims and sandboxes alive in etcd and attempted to restart the pod or pool.SWEEnv.close():If the underlying execution environment (
self.env.close()) threw an exception (e.g. network timeout or dead Docker container), the remainder ofclose()was aborted beforefleet.release(handle)was called. Furthermore,fleet.release()only untracked the handle in memory if it was found infleet._handles; iffleetwasNoneor untracked, no teardown of the claim/sandbox occurred.In
tunix/rl/agentic/trajectory/trajectory_collect_engine.py,TrajectoryCollectEngine.collect()only hadtry ... finally: await self._close()wrapping the final reward calculation. If an exception occurred earlier duringawait self._reset()or inside the rollout stepping loop (await self._one_step()),_close()was never reached, causing any allocated environment/sandbox to leak.ReconcilerErrorfrom Resource Spec Mismatch:In
examples/deepswe/template.py, default or configured CPU requests (SANDBOX_CPU=2500m) could exceed CPU limits (SANDBOX_CPU_LIMIT=2), triggering admission failureReconcilerError: cpu.requests must not exceed cpu.limitson warm pools. Additionally, pod templates lacked anactiveDeadlineSecondssafeguard to automatically reap hung pods.Key Changes
examples/deepswe/swe_env.py:configure_claim_lifecycle(handle, ttl_seconds)to automatically patchspec.lifecycle.shutdownPolicy: "Delete"andttlSecondsAfterFinished: 60on claim acquisition. Even if the client process abruptly crashes or is OOM-killed, Kubernetes garbage collects the claim and sandbox.cleanup_k8s_sandbox_handle(handle)to defensively terminate the sandbox instance, calldelete_claim/delete_sandboxvia cluster resources, and delete remainingsandboxclaimsandsandboxescustom objects viaCustomObjectsApi.SWEEnv._init_agent_sandbox_env()to wrap workspace/env initialization intry ... exceptthat callsself.close()on error before re-raising.SWEEnv.close():self.env.close()andself.workspace.cleanup()intry ... except.fleet.release(handle)tohandle.release().cleanup_k8s_sandbox_handle(handle).__enter__,__exit__) and destructor (__del__) onSWEEnvto guarantee resource cleanup.tunix/rl/agentic/trajectory/trajectory_collect_engine.py:_reset(), thewhile True:stepping loop, and reward computation) insidetry ... finally: await self._close()._close()to handleNoneenv and log any unexpected exceptions during cleanup without masking rollout exceptions.examples/deepswe/template.py:parse_cpu_to_millicores()andparse_memory_to_bytes()utilities.requests <= limits(adjusting limits if requests exceed limits) inget_openhands_pod_template()andget_r2egym_pod_template().activeDeadlineSecondssupport (default 7200s, configurable viaSANDBOX_ACTIVE_DEADLINE_SECONDS).TemplateSpec/ResourceSpecwhenagent_sandbox_rlis not pre-installed.TemplateAndLifecycleTestandTrajectoryCollectEngineLifecycleTestinexamples/deepswe/sandbox_utils_test.pycovering resource parsing, template normalization, claim lifecycle patching, defensive k8s handle cleanup,SWEEnv.close()resilience to exceptions, andTrajectoryCollectEnginecleanup on reset and step errors.tests/rl/agentic/trajectory/trajectory_collect_engine_test.py.sandbox_k8s_e2e_test.pyandsandbox_utils_test.pypass cleanly.