监控自托管 worker 并排查故障
读取队列深度,在不丢失工作的情况下停止会话和 worker,并修复常见的自托管沙箱故障。
本页中的监控调用从您的监控或运维工具中运行,并使用您的 Claude API 密钥进行身份验证。worker 辅助工具会处理认领和保活循环,因此您无需直接调用这些端点。
读取队列深度
client.beta.environments.work.stats() 返回某个环境的队列状态:
| 字段 | 含义 | 用途 |
|---|---|---|
depth | 等待被认领的项目。 | 扩缩您的 worker 集群,或针对积压发出告警。 |
pending | 已被 worker 认领但尚未确认的项目。worker 辅助工具会在处理每个项目之前先确认它,因此在正常运行时该值保持在接近零的水平。 | 检测在认领和确认之间停滞的 worker:针对持续非零的值发出告警。 |
oldest_queued_at | 仍在队列中的最旧项目的时间戳,该项目可能正在等待被认领,也可能已被认领但尚未确认。没有此类项目时为 null。 | 查看最旧的项目已等待了多长时间。 |
workers_polling | 在过去 30 秒内进行过轮询的 worker。 | 针对存活状态发出告警。 |
import os
import anthropic
client = anthropic.Anthropic()
stats = client.beta.environments.work.stats(os.environ["ANTHROPIC_ENVIRONMENT_ID"])
print(f"depth={stats.depth} pending={stats.pending}"){
"type": "work_queue_stats",
"depth": 0,
"pending": 0,
"oldest_queued_at": null,
"workers_polling": 0
}优雅地停止会话
使用 client.beta.environments.work.stop() 请求处理特定会话的 worker 关闭该会话。
默认情况下,工作项会进入 stopping 状态。worker 会在下一次租约心跳时察觉到这一点,取消该会话正在进行的工具调用,并确认关闭。随后工作项变为 stopped。
传入 force=True 可立即将工作项标记为 stopped,而无需等待 worker 的确认。
由于这些调用是从您的运维工具而非 worker 主机运行的,因此不会自动设置 ANTHROPIC_WORK_ID。在运行以下示例之前,请将其设置为目标工作项的 ID。要查找工作项的 ID,请通过 Environments Work 端点列出该环境的工作项。
import os
import anthropic
client = anthropic.Anthropic()
work = client.beta.environments.work.stop(
os.environ["ANTHROPIC_WORK_ID"],
environment_id=os.environ["ANTHROPIC_ENVIRONMENT_ID"],
)
print(work.state)优雅地停止 worker
在会话运行期间被取消的 worker 会在退出前停止其正在进行的工作。如果会话附加了记忆存储,worker 会跳过最终同步,但仍会上传已更改的文件并删除存储目录。
被强制终止的进程不会执行任何清理。要干净地停止 worker:
-
确保 SIGTERM 和 SIGINT 会取消 worker。 具体做法取决于 worker:
Worker 操作 antCLI无需任何操作。CLI 会自行处理这两个信号:它会取消任何正在进行的工具调用,发布其错误结果,并释放工作项。 作为独立进程的 SDK worker EnvironmentWorker不会安装任何信号处理程序。请像独立 worker 示例那样,从信号处理程序中取消 worker。位于 webhook 服务器内的 SDK worker 请像 webhook 示例那样,从服务器自身的关闭钩子中取消 worker。worker 不得接管服务器的信号。 -
使用 SIGTERM 停止 worker,并在任何强制终止之前至少留出 30 秒。 最终上传可能需要这么长时间。默认情况下,Docker 会在发送停止信号 10 秒后发送 SIGKILL。可以通过
docker run上的--stop-timeout,或通过您的编排器的终止宽限期来提高该限制。
如果 worker 在执行清理之前被终止,任何尚未同步的记忆编辑都会丢失。在长期运行的主机上,还需要在下一个附加该存储的会话之前,删除 /mnt/memory/ 下残留的存储目录。仅服务一个会话随后即被丢弃的沙箱无需清理。
故障排除
worker 无法连接
如果 workers_polling 一直为 0,说明 worker 未能连接到队列。请确认 worker 主机上已设置 ANTHROPIC_ENVIRONMENT_KEY 和 ANTHROPIC_ENVIRONMENT_ID。
会话一直处于排队状态
没有 worker 在认领工作。排队中的会话会一直等待,而不会失败。请在读取队列深度中检查 workers_polling 和 depth。
记忆存储挂载失败
worker 会将挂载失败和后台同步失败记录到日志中,而不是报告给会话。只有只读拒绝会以工具错误的形式传达给智能体(请参阅只读存储和冲突)。
如果 worker 在认领会话时无法挂载记忆存储,它会使该工作项失败。会话不会发出错误事件,并保持空闲状态。
| 症状 | 原因 | 解决方法 |
|---|---|---|
worker 日志中包含 the work item carried no sessions token(在 Go 中为 ErrSessionMemoryNoToken 错误),且工作项失败。 | 工作项的每会话 secret 未到达 worker。要么是您的代码没有转发它,要么是您的组织未启用自托管沙箱上的记忆存储。 | 转发工作项的 secret。如果 worker 在同一进程中轮询并运行会话,但仍记录此日志,请联系支持团队。 |
worker 日志中包含 something already exists at the memory store's path。 | 之前会话残留的目录,通常是其 worker 在执行清理之前就被终止的会话。 | 删除日志行中指明的残留目录。其中尚未同步的编辑将会丢失。 |
worker 日志中包含 cannot create the memory store's folder 和 the worker host must make this mount path writable。 | 运行 worker 的用户无法在 /mnt/memory 下创建目录。 | 创建 /mnt/memory 并使用 chown 将其所有者设为该用户。请参阅准备主机。 |
在 worker 认领会话后不久,会话处于 idle 状态,停止原因为 requires_action,且没有错误事件。 | 由于上述原因之一,worker 无法挂载记忆存储,因此使工作项失败。 | 在主机上修复原因,然后发送 user.interrupt 事件。会话的工作会重新排队,下一个认领它的 worker 会重试挂载。 |
自定义工具调用始终没有返回
如果会话以 requires_action 停止原因处于暂停状态,说明没有 worker 或客户端为该工具提供服务。请参阅提供自定义工具。
封装的 MCP 工具调用挂起
如果 MCP 客户端没有设置超时,对封装的 MCP 服务器的挂起调用只有在兜底机制触发时才会变成错误工具结果:
| SDK | 兜底机制 | 触发时间 |
|---|---|---|
| Python | worker 自身的工具调用限制 | 约两分半钟 |
| TypeScript | MCP SDK 的默认请求超时 | 约一分钟 |
| Go | worker 会取消超出其默认限制的工具调用 | 120 秒 |
Was this page helpful?