关于 debug-production-renders
这是一项用于排查 Telecine 渲染工作流的运维技能,覆盖 Postgres、Valkey 队列和 Cloud Run Worker 日志。文档介绍状态与队列检查、故障分析,以及供工程师重试失败渲染的脚本。
主要功能
- 01检查渲染记录和片段状态
- 02查看 Valkey 队列与工作流状态
- 03查询 Cloud Run Worker 日志
- 04诊断 RPC 超时和并发问题
- 05重启失败的渲染
适用场景
- 01沿队列追踪卡住的渲染
- 02结合日志和状态调查片段故障
- 03重新入队初始化任务以重试失败渲染
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ editframe/ skills --skill debug-production-renders安装后在 Claude Code 中输入/debug-production-renders确认已加载。
详细介绍
调试生产渲染
Telecine 渲染任务通过由 Valkey(兼容 Redis)提供支持的队列式流水线流转。每次渲染都是一个 工作流,会经过多个 队列,每个队列都由专用的 Cloud Run 工作服务处理。调试渲染任务时,需要检查三个层面的状态:Postgres 数据库、Valkey 队列状态和 Cloud Run 工作服务日志。
快速开始
所有调试脚本都在 Docker 中运行。在单仓库根目录中执行:
# Full render status: DB row, fragment breakdown, error detail
telecine/scripts/debug-render <render-id>
# Add live Valkey state (queued/claimed/completed/failed jobs)
telecine/scripts/debug-render <render-id> --redis
# Add docker compose log grep (local dev only)
telecine/scripts/debug-render <render-id> --logs
# All three
telecine/scripts/debug-render <render-id> --redis --logs
渲染流水线流程
渲染任务按以下顺序经过各队列:
- process-html-initializer -- 预处理 API 提交的原始 HTML。
- process-html-finalizer -- 设置工作流数据,然后将 render-initializer 作业加入队列。这是 HTML 流水线进入渲染流水线的桥梁。
- render-initializer -- 检出渲染源代码,通过 Electron RPC 提取渲染信息(尺寸、时长、fps),创建资源元数据包,然后分发 N 个片段作业。对于静态图像(png/jpeg/webp),会直接渲染图像并跳过片段。
- render-fragment(N 个并行作业)-- 每个作业通过 Electron RPC 渲染视频的一个时间片段,将片段文件写入存储,并报告进度。
- render-finalizer -- 所有片段作业完成后自动触发。将片段文件合并为最终输出,并将渲染标记为已完成。
流水线由针对 video2.renders 中 INSERT 操作的 Hasura 事件触发。当所有子作业完成或任何作业在重试次数耗尽后失败时,工作流系统会自动将最终处理作业路由到相应队列。
队列名称、工作服务名称和资源分配在源文件中定义——请参见下文的“关键源文件”。
调试脚本
| 脚本 | 用途 |
|---|---|
telecine/scripts/debug-render <id> [--redis] [--logs] | 主要调试工具:数据库状态、片段、错误;可选查看 Valkey 和日志 |
telecine/scripts/inspect-render.ts | 更底层的 Valkey 检查:工作流数据、带有等待时长的已认领作业、所有工作流键 |
telecine/scripts/check-queue.ts | 队列级 Valkey 状态:排队/已认领/失败计数、组织成员关系 |
telecine/scripts/restart-render.ts | 重启失败的渲染:重置数据库状态,并重新将初始化作业加入队列 |
telecine/scripts/create-render.ts | 根据现有渲染任务的组织上下文创建测试渲染 |
telecine/scripts/render-logs [-f] <id> | 在 docker compose 日志中搜索 initializer/fragment/finalizer 服务的日志 |
worktree smoke [branch](运行 telecine/scripts/smoke-test.ts) | 通过公共 API 执行端到端冒烟测试 |
telecine/scripts/smoke-test-waveform.ts | 波形专项冒烟测试:直接向数据库插入渲染任务,并并发测试所有 ef-waveform 模式 |
telecine/scripts/console | Node REPL,支持项目导入(可使用 db、valkey、queues) |
通过以下命令运行 .ts 脚本:telecine/scripts/run tsx scripts/<script>.ts <args>
查询 Cloud Run 日志
没有专用的日志查询脚本。请直接使用 gcloud。工作服务通过 pino 记录结构化 JSON,因此请使用 jsonPayload 过滤器:
# All render workers for a specific render ID
gcloud logging read \
'resource.type="cloud_run_revision"
AND resource.labels.service_name=~"telecine-worker-render"
AND jsonPayload.renderId="<RENDER-ID>"' \
--project=editframe --limit=100 --format=json
# Specific worker stage
gcloud logging read \
'resource.type="cloud_run_revision"
AND resource.labels.service_name="telecine-worker-render-initializer"
AND jsonPayload.renderId="<RENDER-ID>"' \
--project=editframe --limit=100
# Errors only across all workers
gcloud logging read \
'resource.type="cloud_run_revision"
AND resource.labels.service_name=~"telecine-worker"
AND severity>=ERROR
AND jsonPayload.renderId="<RENDER-ID>"' \
--project=editframe --limit=50
Cloud Run 服务名称遵循 telecine-worker-{queue-name} 格式。队列名称完整列表请参见 telecine/deploy/resources/queues/configs.ts。
Valkey 键模式
队列和工作流使用可预测的 Valkey 键模式。了解这些模式后,即使脚本无法满足需求,也能直接查询状态。
队列级键(按队列名称划分):
queues:{queueName}:queued-- 等待领取的作业键组成的有序集合queues:{queueName}:claimed-- 正在处理的作业键组成的有序集合(分数 = 领取时间戳)queues:{queueName}:completed-- 已完成的作业键组成的有序集合queues:{queueName}:failed-- 已失败的作业键组成的有序集合queues:{queueName}:jobs:{jobId}-- 序列化的作业数据(SuperJSON)queues:{queueName}:orgs-- 包含有活动作业的组织键的有序集合
工作流级键(按渲染 ID 划分):
workflows:{renderId}:queued-- 工作流级别待处理作业的有序集合workflows:{renderId}:claimed-- 已领取作业的有序集合workflows:{renderId}:completed-- 已完成作业的有序集合workflows:{renderId}:failed-- 已失败作业的有序集合workflows:{renderId}:data-- SuperJSON 工作流负载(渲染配置)workflows:{renderId}:status-- 工作流状态字符串
进度跟踪:
render:{renderId}-- 用于跟踪片段完成进度的 Redis 流
通过检查分数(领取时间戳)早于 10 秒的已领取作业,可以检测到停滞作业。
数据库表
渲染状态通过 Kysely(而非 Prisma)持久化到 Postgres。db 客户端从 @/sql-client.server 导入。
video2.renders-- 主渲染记录:状态、html、org_id、尺寸、fps、duration_ms、failure_detail、时间戳video2.render_fragments-- 各片段记录:render_id、segment_id、attempt_number、时间戳、last_errorvideo2.process_html-- HTML 处理记录video2.files-- 文件记录(由 process-isobmff 和 ingest-image 使用)
渲染状态值:created -> queued -> rendering -> complete | failed
调试工作流
- 从
debug-render开始 -- 获取数据库状态、错误详情和片段明细。 - 如果卡在 "rendering" 状态 -- 添加
--redis,查看作业是否已排队、已领取(可能停滞),或在 Valkey 中悄然失败。 - 如果 Valkey 状态不明确 -- 使用
inspect-render.ts查看已领取作业的详细等待时间,使用check-queue.ts查看队列级别的计数。 - 如果需要工作进程日志 -- 使用渲染 ID,通过
gcloud查询 Cloud Run 日志(参见上面的命令)。在本地开发环境中,使用--logs标志或render-logs脚本。 - 要重试 -- 使用
restart-render.ts重置数据库状态并重新加入初始化作业。 - 要访问生产数据库 -- 使用
telecine/scripts/debug-prod-web --use-prod-db --shell获取可连接生产数据库的容器。
诊断 Electron RPC 故障
片段渲染会因 RPC 超时而失败。堆栈跟踪会显示渲染进行到了哪一步:
RPC.ts:182— 初始 5 s 计时器触发,未收到任何保持连接消息。Electron 从未开始渲染。原因:调度器打开的连接数超过单个本地容器的处理能力(见下文)、Electron 加载页面失败,或无法创建渲染上下文。RPC.ts:153— 渲染中途保持连接重置计时器触发。至少有一帧在挂起前完成渲染。原因:竞争条件中止了正在进行的 fetch(AbortError情况)、某帧耗时过长,或 Electron 在片段渲染中途崩溃。
AbortError / FrameController 竞争
如果 Electron 日志显示 [EF_FRAMEGEN.beginFrame] error: [object DOMException] / AbortError: The user aborted a request,说明 seekForRender 期间启动的 fetch 被同时触发的自主重新渲染取消。这是依赖时序的竞争条件:媒体加载时会触发 EFTemporal.updated() 或 EFTimegroup.updated(),并调用 FrameController.abort(),从而终止正在进行的 GCS fetch。
修复方法:在 seekForRender 之前,在 timegroup 上设置 data-no-playback-controller,以禁止自主重新渲染——渲染克隆也使用了相同属性。检查 EF_FRAMEGEN.ts 中的 initialize() 以及 EFTemporal.ts/EFTimegroup.ts 中的 updated()。
本地开发环境中的调度器过度扩缩
在生产环境中,MAX_WORKER_COUNT 控制调度器启动的 Cloud Run 实例数量。本地每个队列只有一个容器。如果调度器打开的 WebSocket 连接数超过单个容器的预期(例如,30 个排队任务对应 30 个连接),那么超出工作器 WORKER_CONCURRENCY 配额的每个并发 renderFragment RPC 调用都会在 Electron 开始处理前,于 RPC.ts:182 超时。
两个调节项及其相互作用:
| 调节项 | 生产环境 | 本地开发 |
|---|---|---|
MAX_WORKER_COUNT | 扩缩容容器数量 | 必须与 docker-compose 中的 scale: 一致(通常为 1) |
WORKER_CONCURRENCY | 每个容器处理的任务数 | 当 MAX_WORKER_COUNT=1 时的有效并行度 |
这两个变量都从 telecine/.env 读取(工作器容器通过 env_file 读取,scheduler-go/docker-compose.yaml 通过 ${VAR:-default} 替换)。修改它们后,需要运行 telecine/scripts/docker-compose up -d(不能只运行 restart),以强制重新创建容器并应用新环境变量。
关键源文件
telecine/scripts/debug-render.ts-- 主要的调试工具实现telecine/scripts/inspect-render.ts-- 低级 Valkey 渲染检查工具telecine/scripts/check-queue.ts-- 队列级 Valkey 状态检查器telecine/scripts/restart-render.ts-- 渲染重启/重试工具telecine/lib/queues/Queue.ts-- 队列基类、键模式telecine/lib/queues/Workflow.ts-- 工作流基类、工作流键模式telecine/lib/queues/Job.ts-- 任务序列化、入队、停滞检测telecine/lib/queues/units-of-work/Render/-- 渲染流水线队列/工作器定义telecine/lib/queues/units-of-work/ProcessHtml/-- HTML 流水线队列/工作器定义telecine/deploy/resources/queues/configs.ts-- 生产队列名称和扩缩容配置telecine/deploy/resources/queues/defineWorker.ts-- Cloud Run 服务定义模板telecine/deploy/resources/constants.ts-- GCP 项目/区域常量telecine/lib/valkey/valkey.ts-- Valkey 连接配置
何时使用此技能
在以下情况下使用此技能:
- 生产环境中的渲染任务卡住、失败或产生意外结果
- 需要追踪渲染任务经过流水线的过程,以查找卡住的位置
- 需要查询特定渲染任务的 Cloud Run 日志
- 需要检查或操作 Valkey 队列状态
- 需要重启失败的渲染任务
- 需要了解渲染流水线架构