错误日志分析
错误信息
json
{
"level": 40, // WARN 级别(非致命错误)
"context": "SnapshotManager",
"msg": "Failed to get initial runner: Error: No available runners"
}
这条日志每 10 秒重复一次 ,来自 SnapshotManager 的定时同步任务。
根本原因
问题出在 availabilityScore 阈值不满足。
数据库中有一条 pending 状态的 snapshot 需要分配初始 runner:
| snapshot | name | state | sandboxClass | initialRunnerId |
|---|---|---|---|---|
0e5a7b23... |
sandbox-extra:0.6 |
pending | container | (空,未分配) |
SnapshotManager 在 handleSnapshotStatePending() 中尝试为这条 snapshot 分配 runner,代码逻辑如下(snapshot.manager.ts:1210-1216):
typescript
const availabilityThreshold =
this.configService.getOrThrow('runnerScore.thresholds.availability') + // 默认 10
this.configService.getOrThrow('runnerScore.thresholds.initialRunnerScoreAddon') // 默认 20
initialRunner = await this.runnerService.getRandomAvailableRunner({
regions: ['us'],
sandboxClass: 'container',
availabilityScoreThreshold: availabilityThreshold, // = 10 + 20 = 30
...
})
而数据库中唯一的 runner:
| name | state | region | sandboxClass | availabilityScore |
|---|---|---|---|---|
| default | ready | us | container | 5 |
findAvailableRunners() 中的过滤条件要求:
typescript
availabilityScore: MoreThanOrEqual(availabilityThreshold) // 要求 >= 30
runner 的 availabilityScore = 5,远低于阈值 30 ,所以被过滤掉,返回空数组,抛出 No available runners。
原因总结
ini
┌─────────────────────────────────────────────────────┐
│ Snapshot (pending) 需要初始 runner │
│ 要求: availabilityScore >= 30 │
│ (availability阈值10 + initialRunnerScoreAddon 20) │
│ │
│ 唯一 Runner: availabilityScore = 5 ❌ 不满足 │
│ │
│ 结果: "No available runners" → 每10秒重试 │
└─────────────────────────────────────────────────────┘
availabilityScore 是一个动态计算的负载评分(基于 CPU/内存/磁盘使用率等),分数越低表示 runner 越空闲。但 initialRunnerScoreAddon 额外加了 20 分的门槛,目的是确保 snapshot 构建只分配到负载很低的 runner。
可能的解决方案
方案 1:降低阈值(推荐,适合开发环境)
在 docker-compose.yaml 中为 API 容器添加环境变量:
yaml
environment:
- RUNNER_INITIAL_RUNNER_SCORE_ADDON=0 # 取消额外门槛(默认20)
# 或
- RUNNER_AVAILABILITY_SCORE_THRESHOLD=0 # 直接降低基础门槛
方案 2:手动更新 runner 的 availabilityScore
sql
UPDATE runner SET "availabilityScore" = 100 WHERE name = 'default';
注意:这个值会被 runner 定期上报覆盖,仅临时有效。
方案 3:删除卡住的 pending snapshot(如果不需要)
sql
DELETE FROM snapshot_region WHERE "snapshotId" = '0e5a7b23-82dd-4fba-abfb-890dcfe754f6';
DELETE FROM snapshot WHERE id = '0e5a7b23-82dd-4fba-abfb-890dcfe754f6';
方案 4:检查 runner 上报机制
availabilityScore=5 说明 runner 上报的分数很低。可以检查 runner 容器日志确认它是否正确上报资源信息:
bash
docker logs daytona-runner-1 --tail 50