Skip to content

架构设计

Sandcut 的核心原则很简单:控制逻辑在边缘,执行逻辑在沙箱

请求链路

text
Client

Worker API

输入大小预探测

Durable Object 租约调度器

Warm 容器会话

FFmpeg 执行

结果流式写入 R2

返回 CDN URL

控制平面负责什么

Worker 负责:

  • Bearer Token 鉴权
  • JSON 请求体校验
  • 带 SSRF 防护的输入 URL 校验
  • 结构化 seek 标准化
  • 输入大小预探测
  • 容器会话租约申请与释放
  • R2 上传编排

这让 Worker 本身保持轻量、确定、容易维护。

执行平面负责什么

容器负责:

  • FFmpeg 命令规划
  • 真正的媒体处理
  • 处理结果的流式输出

这样用户提供的媒体工作负载会被限制在沙箱边界里。

Seek 模型

FFmpeg 的一个核心现实是:性能与精度经常不能同时最大化。Sandcut 直接把这个差异显式暴露出来:

  • fast:把 -ss 放在 -i 前面
  • accurate:把 -ss 放在 -i 后面
  • hybrid:前置粗跳 + 后置细修

对外 API 不允许直接透传原始 -ss,而是统一通过结构化 seek 对象来表达。

流式链路

当前实现刻意避免了早期那种高内存路径:

  • 容器用 fs.createReadStream() 输出结果文件
  • Worker 直接把 response.body 传给 OUTPUT_BUCKET.put()

这意味着 Worker 不需要把整个处理结果先完整读进内存再上传。

调度器设计

Durable Object 调度器基于“租约”工作,优先选择:

  1. 活跃任务数更少的会话
  2. 在活跃任务数相同的情况下,更久未被使用的会话

相比只用 KV 轮询,这种方式在并发下更稳定。

已知权衡

输入大小预探测在源站提供 Content-Length 或支持 Range 时效果很好;如果源站两者都不提供,那么要做到字节级硬切断,仍然需要一个受控下载层放在 FFmpeg 前面。

为沙箱化媒体工作负载而构建。