# 沙箱持久化
<subtitle>暂停沙箱并在之后恢复到同一状态，保留文件系统与内存中的运行上下文。</subtitle>

沙箱持久化允许您暂停正在运行的沙箱，并在之后恢复到暂停时的状态。

这不仅包括沙箱文件系统中的文件，也包括内存状态：正在运行的进程、已加载的变量、缓存数据等都会被保存下来。

> 暂停的沙箱和沙箱快照会占用持久化存储，并按持久化存储规则计费。详细计费方式请参考 [计费说明](/docs/agent-sandbox/product/fee.md)。

## 状态流转

了解沙箱在不同状态之间如何切换，有助于更精确地管理生命周期。下面的图展示了常见的状态流转：

```mermaid actions={false}
flowchart TD
    start(( )) -->|Sandbox.create| A

    A["<b>Running</b><br/>• 正在执行任务<br/>• 消耗计算资源"]
    B["<b>Paused</b><br/>• 保留内存和文件<br/>• 不能执行代码"]
    C["<b>Snapshotting</b><br/>• 创建持久化快照<br/>• 短暂暂停执行"]
    D["<b>Killed</b><br/>• 资源已释放<br/>• 不能恢复"]

    A -->|pause| B
    A -->|createSnapshot| C
    B -->|connect| A
    C -->|快照完成| A
    A -->|kill| D
    B -->|kill| D
```

### 状态说明

- **Running**：沙箱正在运行，可以执行代码。这是创建后的初始状态。
- **Paused**：沙箱执行被挂起，但状态会被保留。
- **Snapshotting**：沙箱正在创建持久化快照。创建过程中沙箱会短暂暂停，完成后自动回到 Running 状态。
- **Killed**：沙箱已终止，资源被释放。这是终态，无法恢复。

### 切换沙箱状态

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create()  # 创建后进入运行中状态
sandbox_id = sandbox.sandbox_id

# 暂停沙箱：运行中 -> 已暂停
sandbox.pause()

# 恢复沙箱：已暂停 -> 运行中
same_sandbox = Sandbox.connect(sandbox_id)

# 销毁沙箱：运行中/已暂停 -> 已销毁
same_sandbox.kill()
```

## 暂停沙箱

调用 `pause()` 后，沙箱的文件系统和内存状态都会被保存。您可以将沙箱 ID 保存到数据库或业务状态中，稍后用它恢复同一个沙箱。

```python
from ucloud_sandbox import Sandbox

sbx = Sandbox.create()
print("沙箱已创建", sbx.sandbox_id)

# 暂停沙箱，并保存 sbx.sandbox_id 以便之后恢复
sbx.pause()
print("沙箱已暂停", sbx.sandbox_id)
```

## 恢复沙箱

恢复沙箱时，它会回到暂停时的状态。文件系统会被还原，正在运行的进程、已加载的变量和内存数据也会恢复。

```python
from ucloud_sandbox import Sandbox

sbx = Sandbox.create()
print("沙箱已创建", sbx.sandbox_id)

# 暂停沙箱，并保存 ID
sandbox_id = sbx.sandbox_id
sbx.pause()
print("沙箱已暂停", sandbox_id)

# 连接沙箱；如果目标处于已暂停状态，会自动恢复
same_sbx = Sandbox.connect(sandbox_id)
print("已连接沙箱", same_sbx.sandbox_id)
```

## 列出已暂停的沙箱

您可以调用 `Sandbox.list()` 并传入状态过滤条件，列出所有已暂停的沙箱。更多列表查询方式请参考 [列表查询](/docs/agent-sandbox/sdk/sandbox/08-list.md)。

```python
from ucloud_sandbox import Sandbox, SandboxQuery, SandboxState

# 查询所有已暂停的沙箱
paginator = Sandbox.list(
    query=SandboxQuery(state=[SandboxState.PAUSED]),
)

# 获取第一页
sandboxes = paginator.next_items()

# 获取剩余分页
while paginator.has_next:
    items = paginator.next_items()
    sandboxes.extend(items)

for sbx in sandboxes:
    print("已暂停沙箱", sbx.sandbox_id)
```

## 删除已暂停的沙箱

如果不再需要某个已暂停的沙箱，请调用 `kill()` 删除它。删除后，该沙箱无法恢复。

```python
from ucloud_sandbox import Sandbox

sbx = Sandbox.create()
sbx.pause()

# 通过实例删除
sbx.kill()

# 也可以通过沙箱 ID 删除
Sandbox.kill(sbx.sandbox_id)
```

## 沙箱超时

连接沙箱时，超时时间会被重置。默认超时时间是 5 分钟，也可以在 `Sandbox.connect()` 中传入自定义超时时间：

```python
from ucloud_sandbox import Sandbox

sbx = Sandbox.connect("your-sandbox-id", timeout=60)  # 60 秒
```

## 自动暂停

自动暂停在创建沙箱时通过生命周期配置启用。将 `on_timeout` 设置为 `pause` 后，沙箱超时不会被销毁，而是自动进入已暂停状态。

```python
from ucloud_sandbox import Sandbox

sandbox = Sandbox.create(
    timeout=10 * 60,  # 可选：将超时时间设置为 10 分钟
    lifecycle={
        "on_timeout": "pause",  # 超时后自动暂停
        "auto_resume": False,   # 可选，默认值为 False
    },
)
```

自动暂停是持久化配置：如果沙箱恢复后再次超时，它仍会再次自动暂停。

如果调用 `.kill()`，沙箱会被永久删除，无法再次恢复。

## 网络连接

如果沙箱中运行着对外提供服务的进程，例如 Web 服务，暂停沙箱后该服务将无法从外部访问，已有客户端连接也会断开。

恢复沙箱后，服务会重新变为可访问；但外部客户端需要重新建立连接。

## 限制与注意事项

### 暂停与恢复耗时

- 暂停沙箱大约每 1 GiB 内存需要 **4 秒**
- 恢复沙箱通常大约需要 **1 秒**

### 已暂停沙箱保留时间

- 已暂停的沙箱会一直保留，直到您主动删除
- 您可以在之后任意时间恢复已暂停的沙箱

### 连续运行上限

- 沙箱在不暂停的情况下，单次连续运行上限为 **24 小时**
- 沙箱暂停并恢复后，连续运行时间会重新计算
