Admin: Assets 诊断端点
阶段 G 新增的只读排障端点。挂载在
/admin/assets/diagnostics/*。权限:
site:admin(通过 JWT 认证 +grants表校验) 可用模式:仅selfhosted分页:?limit=50&offset=0(默认 50,上限 200)所有端点都只读,不触发任何清理动作。清理由
assets-worker的 60s reconcile 循环承担。
响应体通用结构
{
"items": [...],
"total": <number>,
"limit": <number>,
"offset": <number>,
"notice": "(说明该端点语义与限制的短文本)"
}1. GET /admin/assets/diagnostics/orphan-workspace-locks
查询语义:asset_disks.locked_by_asset_id IS NOT NULL AND deleted_at IS NULL, 且(持锁资产在 assets_items 中不存在 / 已软删除 / 状态不在 starting/creating/running/stopping)。
响应 item 字段:
| 字段 | 说明 |
|---|---|
| workspace_id | asset_disks.id(兼容命名,对应 workspaceId) |
| project_id | |
| folder_key | _disks::<id> |
| locked_by_asset_id | 持锁资产 ID |
| locked_at | ISO8601 |
| lock_mode | write |
| suspected_reason | asset_missing / asset_deleted / asset_not_running |
| asset_status | 持锁资产当前状态(可为 null) |
| asset_deleted_at | 持锁资产软删除时间(可为 null) |
2. GET /admin/assets/diagnostics/final-sync-failures
查询语义:assets_items.deleted_at IS NULL AND (status_message ILIKE 'workspace_final_sync_failed:%' OR ILIKE 'runtime_release_failed:%')。
语义限制:这是当前残留查询,不是历史事件查询。asset 后续成功启停会覆盖 status_message。 真正的事件持久化留给阶段 G 之后(接入 Sentry/OpenTelemetry 后可直接查外部 sink)。
响应 item 字段:
| 字段 | 说明 |
|---|---|
| asset_id | |
| status | |
| status_message | 含 workspace_final_sync_failed: / runtime_release_failed: 前缀 |
| updated_at | |
| project_id | |
| cloud_provider_id | 兼容字段 |
| spec_id | cloud_spec_id ?? compute_spec_id 的统一视图 |
3. GET /admin/assets/diagnostics/host-path-residue
查询语义:DB 候选集(asset_disks 中 lock_mode='none' 或关联 asset 不存在/已删除/非运行)
AssetDiskSyncService.hostPathExists(diskId)文件系统核验。
响应 item 字段:
| 字段 | 说明 |
|---|---|
| disk_id | asset_disks.id |
| project_id | |
| folder_key | _disks::<id> |
| lock_mode | none 或 write |
| locked_by_asset_id | 可为 null |
| asset_status | 关联资产状态(若有) |
| asset_deleted_at | 关联资产软删除时间(若有) |
| host_path | AssetDiskSyncService.getHostPath(diskId) 计算结果 |
4. GET /admin/assets/diagnostics/runtime-residue
查询语义:assets_items.provider_resource_id IS NOT NULL AND status IN ('stopped','error') AND deleted_at IS NULL。
响应 item 字段:
| 字段 | 说明 |
|---|---|
| asset_id | |
| provider_name | local-docker / cloud:<uuid> |
| provider_resource_id | 运行时 ID(容器 ID / ECI instance 等) |
| status | stopped / error |
| status_message | |
| cloud_provider_id | |
| spec_id | cloud_spec_id ?? compute_spec_id |
| updated_at | |
| project_id |
curl 样例
# 拉取最近 20 条 orphan-workspace-locks
curl -H "Authorization: Bearer $JWT" \
'https://block2.wainao.chat/admin/assets/diagnostics/orphan-workspace-locks?limit=20'
# 拉取全部 runtime-residue
curl -H "Authorization: Bearer $JWT" \
'https://block2.wainao.chat/admin/assets/diagnostics/runtime-residue?limit=200'与生命周期事件的关系
诊断端点给出当前状态快照;事件流([asset-lifecycle] 日志)给出过程记录。 两者互补:
- 想知道"现在有没有问题"→ 诊断端点
- 想知道"刚刚发生了什么"→ lifecycle 日志 +
jq
详见仓库内 docs/features/assets/observability.md。
权限错误
- 401:缺 JWT
- 403:JWT 有效但不具
site:admin权限 - 501:在非 selfhosted 模式访问