> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cleanup patterns

> Patterns for reliable sandbox cleanup and resource management.

This guide covers resource management and cleanup strategies for sandboxes. Reliable cleanup prevents orphaned sandboxes after a script exits, which keeps costs predictable and avoids unintentional compute resource usage. The patterns here apply to scripts that create one or many sandboxes, with or without an explicit session.

## Automatic cleanup

Automatic cleanup ties a sandbox's lifetime to a Python construct (a context manager or the running process) so the SDK releases resources without explicit `stop()` calls.

### Context managers (recommended)

Context managers are the recommended pattern because they guarantee cleanup even if the enclosed code raises an exception. The SDK stops sandboxes when the context exits:

```python theme={"system"}
from cwsandbox import Sandbox

with Sandbox.run() as sandbox:
    result = sandbox.exec(["echo", "hello"]).result()
# sandbox.stop() called automatically
```

Sessions clean up all their sandboxes:

```python theme={"system"}
import cwsandbox
from cwsandbox import SandboxDefaults

with cwsandbox.Session(SandboxDefaults(container_image="python:3.11")) as session:
    sb1 = session.sandbox()
    sb2 = session.sandbox()
# Both sandboxes stopped automatically
```

### Global cleanup handlers

For cases where a context manager isn't practical, the SDK registers cleanup handlers that run when the process terminates:

| Scenario           | Behavior                                    |
| ------------------ | ------------------------------------------- |
| Normal script exit | `atexit` handler stops all sandboxes        |
| Ctrl+C (`SIGINT`)  | Signal handler stops all sandboxes          |
| `SIGTERM`          | Signal handler stops all sandboxes          |
| Second Ctrl+C      | Force exit (prevents unresponsive shutdown) |

## Manual cleanup

Use manual cleanup when you need explicit control over when to release a sandbox or session. Manual cleanup lets you pass stop options or coordinate cleanup across long-running code.

### Sandbox stop()

```python theme={"system"}
sandbox = Sandbox.run()
result = sandbox.exec(["echo", "hello"]).result()
sandbox.stop().result()

# With options
sandbox.stop(graceful_shutdown_seconds=30.0).result()
sandbox.stop(snapshot_on_stop=True).result()
```

### Session close()

```python theme={"system"}
from cwsandbox import SandboxDefaults

session = cwsandbox.Session(SandboxDefaults(container_image="python:3.11"))
sandbox = session.sandbox()
# ...
session.close().result()  # Stops all sandboxes
```

### Batch cleanup

```python theme={"system"}
from cwsandbox import results

sandboxes = [Sandbox.run() for _ in range(5)]
# ... use sandboxes ...
results([sb.stop() for sb in sandboxes])  # Stop all in parallel
```

## Orphan management

Orphans are sandboxes that outlive the process that created them. The following sections describe how to make orphans easy to find, how to query for them, and how to bring them back under managed cleanup.

### Tagging for discovery

The SDK's automatic cleanup handlers prevent most orphans. Sandboxes can keep running after forced shutdowns (`kill -9`), network failures, or when you create sandboxes outside of sessions and context managers. Use tags to make any orphans discoverable later.

```python theme={"system"}
from cwsandbox import Sandbox, SandboxDefaults

# Tag at creation time
defaults = SandboxDefaults(
    container_image="python:3.11",
    tags=("my-project", "batch-job-123"),
)

with Sandbox.run(defaults=defaults) as sandbox:
    result = sandbox.exec(["echo", "hello"]).result()
```

Good tagging practices:

* Project or application name (`my-project`)
* Job or run identifier (`batch-job-123`, `run-2024-01-15`)
* Environment (`dev`, `staging`, `prod`)

### Find orphaned sandboxes

Query by tags to find sandboxes from previous runs:

```python theme={"system"}
from cwsandbox import Sandbox

orphans = Sandbox.list(tags=["my-project"]).result()
for sandbox in orphans:
    sandbox.stop().result()
```

### Session adoption

Adopting an orphan attaches it to a session so the session governs its lifetime. The orphan then receives the same automatic cleanup guarantees as newly created sandboxes:

```python theme={"system"}
import cwsandbox
from cwsandbox import SandboxDefaults

with cwsandbox.Session(SandboxDefaults(container_image="python:3.11")) as session:
    orphans = session.list(tags=["my-project"]).result()
    for sandbox in orphans:
        session.adopt(sandbox)
# All adopted sandboxes cleaned up with session
```

### Delete by ID

When you already know a sandbox's ID, you can delete it directly without listing or adopting it first:

```python theme={"system"}
from cwsandbox import Sandbox

Sandbox.delete("sandbox-abc123").result()
Sandbox.delete("sandbox-abc123", missing_ok=True)  # Ignore if gone
```
