Skip to content

perf(aws-lambda): warm the audio function while the plan runs - #6148

Merged
miguel-heygen merged 4 commits into
mainfrom
perf/lambda-warm-render-fn
Oct 23, 2026
Merged

miguel-heygen merged 4 commits into
mainfrom
perf/lambda-warm-render-fn

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

What

A render on a stack with the arm64 video function now starts the x86 render function's container at the very beginning, in a fire-and-forget invoke, so it is warm when the audio task needs it. A stack without a video function is unchanged: same states, same cost.

Why

On an arm64 stack the plan and the chunks run on the arm64 video function, so the x86 function that mixes the audio is cold when the audio task starts. A cold audio task takes 3 to 5 s longer, and it finished after the last chunk in most renders, so the render waited for it.

Related work

Follows the arm64 video function work; no overlapping PR.

How

  • New WarmRender state in the SAM template. It invokes the render function with InvocationType: Event and Action: warm. A failed or throttled warm-up is caught and the render goes on, so it can never fail a render.
  • A rule in SelectPlanProtocol sends a v2 render to WarmRender only when the stack has the video function (the template's own HasVideoFunction condition decides the value compared). Without a video function that rule can never match, so the render takes the old path with no extra state or transition. The CDK stack has no video function and is not touched.
  • The handler answers warm before any event parsing: it resolves Chrome, the part of the cold start the audio task would otherwise pay, and returns.

Test plan

Measured on one arm64 stack, a 30-minute 1080p composition, 3 runs with the change and 3 without, interleaved on the same stack with nothing else running:

  • Median wall time: 8.1% lower (the time the audio task outlasts the last chunk fell from 6.0 to 6.9 s down to 1.2 to 3.7 s).

  • Cost per render: flat (+0.1% at the median), the extra invoke is below the noise.

  • Unit tests added/updated (handler answers warm without touching S3, and that test fails without the handler change; a template test pins the video-function gate and the caught failure)

  • Manual testing performed: the timing stack above, plus a real deploy of the final template as an arm64 stack and as an x86-only stack, one small render each. The arm64 execution enters WarmRender before PlanV2; the x86-only execution goes straight to PlanV2.

  • Documentation updated (not applicable)

  • Comments follow CONTRIBUTING.md "Comments"

The audio task runs on the x86 render function, which is cold when the plan ran on the arm64 video function. A fire-and-forget invoke at the start of a render now wakes it, so the audio no longer outlasts the chunks.
…eo function

An x86-only stack has no cold function to warm, so it takes the old path with no extra step. The CDK stack has no video function and is unchanged.

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: REQUEST CHANGES · 1 blocker · 0 important · 0 nits

The logic is fine. The only problem is that CI Format and Windows Preflight fail on oxfmt --check for the new test (see inline). Run bun run format and this is an approve.

Scope

Read all 5 files at a25f2acf. Checked: the warm short-circuit sits before unwrapEvent, so the never exhaustiveness check still holds. ensureChromePath is the same per-container cache the audio task uses. The state-machine role already has lambda:InvokeFunction on RenderFunction. The !If gate means an x86-only stack can never take the warm branch, and Catch → PlanV2 keeps a failed warm-up from failing the render. The SDK always sends PlanProtocol, so the Default path not warming has no effect. The CDK stack is intentionally untouched. Other CI jobs were still running when this was posted. No prior reviews.

Comment on lines +171 to +174
const choices = requireRecord(states.SelectPlanProtocol, "SelectPlanProtocol").Choices as Record<
string,
unknown
>[];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocker: oxfmt --check (0.41.0) rejects this wrap, so the required CI Format job fails at this head. This is the formatter's output:

Suggested change
const choices = requireRecord(states.SelectPlanProtocol, "SelectPlanProtocol").Choices as Record<
string,
unknown
>[];
const choices = requireRecord(states.SelectPlanProtocol, "SelectPlanProtocol")
.Choices as Record<string, unknown>[];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Fixed in b409640

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 0 blocker · 0 important · 0 nits — 1 resolved, 0 open, 0 new · a25f2ac → b409640. The delta is exactly the formatter suggestion, and CI Format is green.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit fb2f7c1 Oct 23, 2026
69 of 71 checks passed
@miguel-heygen
miguel-heygen deleted the perf/lambda-warm-render-fn branch October 23, 2026 19:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant