Skip to main content
This guide covers using Session to manage multiple sandboxes with shared configuration. It’s for client developers who need to coordinate groups of sandboxes, apply common defaults, and ensure consistent cleanup across a workload.

Session overview

A Session provides:
  • Shared default configuration for all sandboxes.
  • Automatic cleanup when the session closes.
  • A scope for the @session.function() decorator.

Basic usage

import cwsandbox
from cwsandbox import SandboxDefaults

# Define shared configuration
defaults = SandboxDefaults(
    container_image="python:3.11",
    tags=("project-alpha",),
)

# Create a session with context manager
with cwsandbox.Session(defaults=defaults) as session:
    # Create sandboxes through the session
    sb1 = session.sandbox()
    sb2 = session.sandbox()

    # Use the sandboxes
    result1 = sb1.exec(["echo", "sandbox 1"]).result()
    result2 = sb2.exec(["echo", "sandbox 2"]).result()

# All sandboxes automatically stopped when exiting context

Create sandboxes

The following sections describe how to create sandboxes through a session and override session defaults.

session.sandbox()

Creates a sandbox with session defaults. The sandbox doesn’t start until first use:
with cwsandbox.Session(defaults=defaults) as session:
    # sandbox() returns an unstarted sandbox
    sandbox = session.sandbox()

    # Operations auto-start the sandbox on first use
    result = sandbox.exec(["echo", "hello"]).result()
For explicit control over when the start RPC fires:
with cwsandbox.Session(defaults=defaults) as session:
    sandbox = session.sandbox()
    sandbox.start().result()  # Explicit start
    sandbox.wait()            # Wait for RUNNING
    result = sandbox.exec(["echo", "hello"]).result()

Override defaults

Pass additional arguments to override session defaults:
from cwsandbox import ResourceOptions

# Session with base configuration
defaults = SandboxDefaults(
    container_image="python:3.11",
    tags=("my-project",),
)

with cwsandbox.Session(defaults=defaults) as session:
    # Override image and resources for this sandbox
    gpu_sandbox = session.sandbox(
        command="sleep",
        args=["infinity"],
        container_image="pytorch/pytorch:latest",
        resources=ResourceOptions(
            requests={"cpu": "4", "memory": "16Gi"},
            limits={"cpu": "8", "memory": "32Gi"},
            gpu={"count": 1},
        ),
        tags=["gpu-workload"],  # Merged with session tags
    )
See the Sandbox configuration guide for all available options.

Multiple sandbox management

Sessions work well for managing sandbox pools:
with cwsandbox.Session(defaults=defaults) as session:
    # Create a pool of sandboxes
    sandboxes = [
        session.sandbox()
        for _ in range(5)
    ]

    # Distribute work across the pool
    processes = [
        sb.exec(["python", "-c", f"print({i})"])
        for i, sb in enumerate(sandboxes)
    ]

    # Collect results
    results = [p.result() for p in processes]

# All 5 sandboxes automatically cleaned up

Session lifecycle

The following sections describe how to close a session, what close() does, and how to handle errors.

Manual close

When you don’t use a context manager, close a session explicitly:
session = cwsandbox.Session(defaults=defaults)

sandbox = session.sandbox()
result = sandbox.exec(["echo", "hello"]).result()

# Close the session (stops all sandboxes)
session.close().result()

What close() does

Calling close() performs the following actions:
  1. Stops all sandboxes created through the session.
  2. Waits for cleanup to complete.
  3. Returns OperationRef[None].

Error handling

Sessions clean up even if exceptions occur:
with cwsandbox.Session(defaults=defaults) as session:
    sandbox = session.sandbox()
    raise RuntimeError("Something went wrong!")
# Sandbox is still cleaned up

Adopt external sandboxes

Bring sandboxes created outside the session under session management:
import cwsandbox
from cwsandbox import Sandbox

with cwsandbox.Session(defaults=defaults) as session:
    # Find existing sandboxes
    existing = Sandbox.list(tags=["orphaned-work"]).result()

    # Adopt them for cleanup
    for sandbox in existing:
        session.adopt(sandbox)

    # Now session.close() will clean them up too

Session properties

Inspect session state with built-in properties such as sandbox_count:
session = cwsandbox.Session(defaults=defaults)

# Number of sandboxes tracked
print(session.sandbox_count)  # 0

sandbox = session.sandbox()
print(session.sandbox_count)  # 1

When to use sessions

Use caseRecommended approach
Single sandbox, simple taskSandbox.run() with context manager
Multiple sandboxes, shared configSession
Function decorator APISession required
Pool of workersSession
One-off commandDirect Sandbox.run()

Without sessions

You don’t need sessions for single sandboxes:
from cwsandbox import Sandbox

# Direct usage without session
with Sandbox.run() as sandbox:
    result = sandbox.exec(["echo", "hello"]).result()
# Cleanup handled by context manager
Last modified on May 29, 2026