部署

AWS Lambda

将分布式 HyperFrames 渲染部署到 AWS Lambda,并从笔记本电脑或 CI 驱动渲染。

HyperFrames 提供了原生的 AWS Lambda 部署方案:一个 Lambda 函数作为 Step Functions 标准工作流的前端,将渲染任务分散到多个并行的 chunk worker 上执行,中间产物存储在 S3 中。配置好 AWS 凭证后,端到端只需三条命令。

hyperframes lambda deploy
hyperframes lambda render ./my-project --width 1920 --height 1080 --wait
hyperframes lambda destroy

variables 的模板同样可以在同一个 Lambda 栈上运行——在 composition 上声明 data-composition-variables,然后每次渲染时通过 --variables 传入值,或使用 lambda render-batch 进行批量渲染。详情请参阅 Templates on Lambda 指南,了解个性化渲染流程(单次渲染、JSONL 批量渲染、SDK 编程式调用)以及 256 KiB 的 Step Functions 执行输入限制。

架构

┌──────────────────────────────────────────────────────────────────┐
│ Step Functions 状态机                                              │
│   Plan → Map(N) RenderChunk → Assemble                           │
└──────────────────────────────────────────────────────────────────┘
│ 根据 event.Action 分发
▼
┌──────────────────────────────────────────────────────────────────┐
│ 单个 Lambda 函数 (packages/aws-lambda/dist/handler.zip)           │
│   handler.mjs                                                    │
│     ├─ Action="plan"        → @hyperframes/producer/distributed  │
│     ├─ Action="renderChunk" → @hyperframes/producer/distributed  │
│     └─ Action="assemble"    → @hyperframes/producer/distributed  │
│   bin/ffmpeg                — ffmpeg-static                      │
│   node_modules/@sparticuz/chromium/ — Lambda 优化的 Chromium      │
└──────────────────────────────────────────────────────────────────┘
│ 基于本地路径的纯函数
▼
┌──────────────────────────────────────────────────────────────────┐
│ S3 存储桶 — plan 压缩包 + 每个 chunk 的输出 + 最终 mp4            │
└──────────────────────────────────────────────────────────────────┘

Lambda 处理函数是一个轻量的调度层:解析 Step Functions 事件,从 S3 下载输入到 /tmp,调用 @hyperframes/producer/distributed 的开源原语,将输出上传回去,返回一个小型 JSON 结果。所有重活——捕获、编码、音频混音——都在开源原语内部完成。

前置条件

工具用途安装方式
AWS 凭证CLI 和部署步骤都需要调用 AWS API。环境变量、~/.aws/credentials、SSO 或 IMDS——任何 boto3 可以解析的凭证链。
AWS SAM CLIhyperframes lambda deploy/destroy 会调用 sam deploy/sam delete安装指南
bun部署时用于构建 packages/aws-lambda/dist/handler.zipnpm install -g bunbun.sh
HyperFrames 仓库检出lambda deploy 从源码构建 Lambda 处理函数 ZIP。如果在仓库外部署,可以设置 HYPERFRAMES_REPO_ROOT 指向仓库路径。git clone https://github.com/heygen-com/hyperframes

三种部署路径

路径 1 — hyperframes lambda CLI(推荐)

CLI 是对 SAM 模板 + @hyperframes/aws-lambda SDK 的轻量封装。对于大多数用户来说,这是正确的起点。

hyperframes lambda deploy \
--stack-name=hyperframes-prod \
--region=us-east-1 \
--concurrency=8 \
--memory=10240

默认的 --concurrency=8 对新用户来说是刻意保守的设置。Lambda Map 状态的默认值允许无限数量的 chunk 并行执行;8 可以将失控渲染的最坏情况花费限制在大约 8 × (15 min × 10 GB × $0.0000167/GB-s) ≈ $1.20。在确定了典型渲染的 chunk 数量后,可以适当提高该值。

部署后,使用以下命令渲染任何项目:

hyperframes lambda render ./my-project --width 1920 --height 1080 --wait

--wait 标志会阻塞并流式输出每个 chunk 的进度和累计费用;去掉该标志可以异步执行,然后按自己的节奏使用 hyperframes lambda progress <renderId> 轮询。

完整的标志文档请参阅 CLI 参考

使用 sites create 预先暂存项目

每次 lambda render 调用时重复渲染同一项目树会重新打包和上传。对于紧密的内部循环(CI 冒烟测试、demo 流程中的 prompt 迭代),可以预先暂存项目并复用上传:

hyperframes lambda sites create ./my-project
# → Site ID: a1b2c3d4e5f6g7h8 (content-addressed)

hyperframes lambda render ./my-project --site-id=a1b2c3d4e5f6g7h8 \
--width 1920 --height 1080 --wait

siteId 通过项目树的 SHA-256 哈希实现内容寻址;对未更改的树重新运行 sites create 会通过 HeadObject 短路跳过上传。将相同的 --site-id 传递给任意多次 lambda render 调用——它们都复用同一个 S3 PUT。

路径 2 — 直接 SAM 部署

如果你想在部署前查看 CloudFormation,或者需要自定义拓扑(额外的告警、SNS 订阅者、KMS 密钥等),可以直接对 examples/aws-lambda/template.yaml 模板调用 SAM:

cd packages/aws-lambda
bun run build:zip                     # 生成 dist/handler.zip
cd ../../examples/aws-lambda
sam deploy \
--stack-name=hyperframes-prod \
--region=us-east-1 \
--resolve-s3 \
--capabilities CAPABILITY_IAM \
--no-confirm-changeset \
--parameter-overrides ChromeSource=sparticuz ReservedConcurrency=8

该模板会输出三个 CloudFormation 输出值,你需要它们来调用渲染:

  • RenderBucketName — 用于存储 plan 压缩包 + 每个 chunk 的输出 + 最终渲染结果的 S3 存储桶。
  • RenderStateMachineArn — 编排 Plan → Map → Assemble 的 Step Functions 标准工作流。
  • RenderFunctionArn — 状态机调度的单个 Lambda 函数。

⚠️ Warning

SAM 模板自身的 ReservedConcurrency 默认值为 -1(未预留,使用账户默认值)。路径 1 的 CLI 将其覆盖为 8 以限制首次使用的费用;如果在这里从 --parameter-overrides 中去掉 ReservedConcurrency,则使用未预留的默认值。除非你已经确定了典型渲染的 fan-out 规模,否则请显式设置该值。

路径 3 — CDK 构造

对于已经使用 CDK 的用户,@hyperframes/aws-lambda 包导出了一个 HyperframesRenderStack L2 构造,生成与 SAM 模板相同的拓扑:

import { App, CfnOutput, Stack } from "aws-cdk-lib";
import { HyperframesRenderStack } from "@hyperframes/aws-lambda/cdk";

const app = new App();
const stack = new Stack(app, "MyApp");
const render = new HyperframesRenderStack(stack, "Render", {
projectName: "hyperframes",
lambdaMemoryMb: 10240,
reservedConcurrency: 8,
chromeSource: "sparticuz",
});

new CfnOutput(stack, "RenderBucketName", { value: render.bucket.bucketName });
new CfnOutput(stack, "StateMachineArn", { value: render.stateMachine.stateMachineArn });

aws-cdk-libconstructs 被声明为 @hyperframes/aws-lambda可选对等依赖,因此只需要 SDK 的用户无需承担 CDK 的导入开销。

该构造暴露了 .bucket.renderFunction.stateMachine,方便你在旁边接入仪表盘、SNS 主题或其他 AWS 资源,无需重新推导 ARN。

IAM 权限

CLI 内置了 IAM 引导流程,避免首次部署时出现 "User is not authorized to perform iam:CreateRole" 错误:

# 打印需要附加到运行 CLI 的 IAM 用户的内联策略文档。
hyperframes lambda policies user

# 打印 CloudFormation 服务角色的 { TrustRelationship, InlinePolicy }。
hyperframes lambda policies role --principal=cloudformation

# 验证已签入的策略是否仍然满足 CLI 的需求(缺失时以非零状态退出)。
hyperframes lambda policies validate ./infra/iam/hyperframes-deploy.json

生成的文档对 CLI 所需的操作集授予 Resource: "*"。首次成功部署后,你可以将 Resource 缩小到已部署的 ARN——根据上述 CloudFormation 输出可以预测。在 CI 中运行 CLI 的用户通常将策略文档签入源码管理,并在部署前运行 policies validate 以捕获策略偏移。

费用结构

Lambda 渲染按 GB-秒计费(Lambda 计费时长 × 配置内存),另外 Step Functions 标准工作流还有少量的每次状态转换费用。hyperframes lambda progress 会显示实时费用统计:

hyperframes lambda progress my-render-id
# Status:    SUCCEEDED
# Progress:  100%
# Frames:    480 / 480
# Lambdas:   5
# Cost:      $0.0214 (Lambda $0.0210 + SFN $0.0004)
# Output:    s3://hyperframes-renders/.../output.mp4

费用数值为尽力估算:Lambda 计费时长来自处理函数自身的 DurationMs 返回值(SFN 历史记录会在成功载荷中展示),S3 传输费用不包含在内。如果你想验证,计算逻辑在 packages/aws-lambda/src/sdk/costAccounting.ts 中;CLI 显示的数值与 AWS 账单报告基本一致(在四舍五入误差范围内)。

故障排除

sam deploy 报错 "Stack already exists"

传入与首次相同的 --stack-name。SAM 是幂等的——对现有栈重新运行会解析为空操作或就地更新。

User is not authorized to perform iam:CreateRole

运行 lambda deploy 的 IAM 凭证没有权限创建 CloudFormation 所需的服务角色。运行 hyperframes lambda policies user 并将打印的策略附加到你的 IAM 用户(或者获取 policies role 输出,让管理员创建部署角色)。

Lambda function failed: PLAN_HASH_MISMATCH

Step Functions 调用 renderChunk 时使用的 plan 哈希与 S3 上的 planDir 不匹配。几乎总是因为本地 plan() 构建和已部署的 Lambda ZIP 之间的 producer 版本不同。重新运行 hyperframes lambda deploy(会重新构建 ZIP)并重新渲染。

Lambda function failed: BROWSER_GPU_NOT_SOFTWARE

处理函数启动了 Chromium,但运行时探测发现了非 SwiftShader 的 GL 后端。硬件 GL 在 chunk 边界处是非确定性的,因此分布式渲染在运行时镜像/启动标志层(而非 composition 层)拒绝它。重新构建处理函数 ZIP 并重新部署:

bun run --cwd packages/aws-lambda build:zip
hyperframes lambda deploy --stack-name=<your-stack>

构建流程固定了 @sparticuz/chromium + Chrome 标志(--use-gl=swiftshader --use-angle=swiftshader),因此重新部署几乎总能解决此问题。如果问题仍然存在,说明你的栈的 Lambda 函数指向了之前部署的过时处理函数 ZIP——lambda deploy 总是会重新构建,因此重新运行可以解决。

渲染似乎卡在 RUNNING

最常见的原因是多 chunk 渲染上的 Lambda 冷启动链。Map 状态的预留并发数限制了可以并行运行的 chunk 数量——如果你设置了 --concurrency=4 而你的渲染有 16 个 chunk,状态机将分批处理(每批 4 个)。hyperframes lambda progress <id> 显示当前正在进行的调用数量。

如果进度超过 10 分钟没有推进,请在 AWS 控制台中检查 Step Functions 执行——失败的 Lambda 调用包含类型化的错误名称(FONT_FETCH_FAILEDFFMPEG_VERSION_MISMATCH 等),这些错误会使状态机短路。

销毁不会回收 S3 存储

渲染存储桶在创建时使用了 CloudFormation 的 Retain 删除策略——hyperframes lambda destroy(或 sam delete)会销毁函数和状态机,但存储桶会保留。这是有意为之:保护最终渲染的 MP4 不会在重新部署时丢失。要完全回收存储,请通过 AWS 控制台 / aws s3 rb 清空并删除存储桶。

v1 版本中不包含的功能

  • 完成时 Webhooks。 v1 不包含——使用 hyperframes lambda progress 轮询或查看 Step Functions 执行。带 SNS 主题的 --webhook 标志在 Phase 6c 计划中。
  • compositions 发现命令。 将单独提供(计划中的 PR 6.10);目前请将 lambda render 指向包含 index.html 的项目目录。
  • 多区域。 每个 --region 是一个独立的栈。没有内置的跨区域故障转移。
  • HDR。 分布式模式仅支持 SDR。带 bsf 信令的 HDR mp4 在 v1.5 计划中。