5 Commits
Author SHA1 Message Date
Miguel Ángel 03ed14615a feat(aws-lambda): run chunks on an optional arm64 image function (#6065)
* feat(aws-lambda): run chunks on an optional arm64 image function

A new VideoImageUri parameter adds an arm64 container-image function that only
renders chunks. Plan, audio and assemble stay on the x86 ZIP function, so audio
encodes are unchanged. Empty (the default) deploys exactly as before. The
reserved concurrency moves to whichever function renders the chunks.

* docs(aws-lambda): the template tags both render functions

* fix(aws-lambda): nest the arm64 video function so sam deploy needs no image repository

sam deploy refuses a template with any top-level image function unless it is given an image
repository, even when that function's Condition is false, so every deploy of the template failed.
The video function now lives in video-function.yaml, a nested stack created only when
VideoImageUri is set. The release ships it beside template.yaml and the CLI stages both.

A new workflow runs the CLI's sam deploy argv against the template with fake credentials and
requires it to reach the first upload.

* fix(aws-lambda): run the plan on the arm64 video function with the chunks it plans

* refactor(cli): name the staged template directory instead of commenting it

* docs(aws-lambda): say the arm64 image runs the plan as well as the chunks
2026-10-23 00:40:55 +00:00
Miguel Ángel 2a14cbc924 perf(aws-lambda): size distributed renders from account concurrency limits (#5813)
* perf(aws-lambda): run chunks through a Distributed Map to lift the 40-chunk cap

The inline Map runs at most 40 chunk renders at once. Both state machine
definitions (CDK and SAM) now use a Distributed Map with STANDARD child
executions, capped at the function's reserved concurrency so chunks past it
queue instead of being throttled. Progress reads each chunk's child
execution history so frames, cost and chunk errors still show up.

* fix(aws-lambda): retry Lambda throttles for minutes and stop on oversized chunks

A throttled task used to burn its four catch-all retries in about 30 s.
It now gets its own jittered backoff of several minutes, because another
render on the same function can still hold the reserved slots. Plan
treats CHUNK_EXCEEDS_WORKER_TIMEOUT as terminal in both definitions.

* chore(aws-lambda): trim stack comments to keep the comment share flat

* fix(aws-lambda): keep render --wait working at hundreds of chunks

Progress polls read the chunk Map Run's counts (one DescribeMapRun) instead of
every child execution's history, take exact chunk frames and cost from the Map
output once it exits, and read failed children only when the counts show a
failure. The SDK client retries throttled calls up to 8 times with backoff.

* feat(aws-lambda): size each render's concurrency to the account instead of a fixed 8

* fix(lambda): keep the concurrency SDK external in published modules

* fix(cli): keep an existing stack's reserved concurrency on redeploy

Redeploying without --concurrency sent ReservedConcurrency=-1, which
removed the cap of 8 that earlier CLI versions reserved by default and
stopped recording it in the state file. The override is now left out
when the flag is omitted, so SAM keeps the stack's current value (a new
stack still gets the template's unreserved default). The state file
records the deployed value, and deploy prints the kept reservation.

* fix(aws-lambda): keep progress working for callers without DescribeMapRun

Callers whose IAM policy came from an earlier `lambda policies user`
lack states:DescribeMapRun, so reading a running Distributed Map threw
AccessDeniedException out of `lambda progress` and `render --wait`
while the render itself went on to succeed. getRenderProgress now
catches only that error around the map-run read, returns the parent
snapshot (status, plan and assemble progress) and adds a warning to
re-apply the policy, which both commands print. Other errors still
throw.

* fix(cli): let the documented deploy policy drop a reserved concurrency

When a redeploy removes a function's reserved concurrency, CloudFormation
calls lambda:DeleteFunctionConcurrency. The policy printed by
`lambda policies role|user` granted only PutFunctionConcurrency, so the
update failed and rolled back. Grant it, and pin it with
states:DescribeMapRun in the required-actions test.

* fix(aws-lambda): read smoke chunk hashes from the Distributed Map output

With chunks in a Distributed Map, their task results live in child
executions, so the smoke gate's chunk-hash check found 0 chunks in the
parent history and failed every v1/v2 comparison. Read Chunks[] from the
RenderChunks / RenderChunksV2 MapStateExited output instead, as
getRenderProgress does. The stack this script deploys only has the
Distributed Map, so the inline-Map path is gone.

* fix(producer): cap a pinned chunk size at the worker concurrency, not 16

With --chunk-size or --target-chunk-frames and no --max-parallel-chunks,
the plan still capped the render at 16 chunks however many workers the
account allowed, so --chunk-size 30 on a 60 s render gave 16 chunks of
113 frames. The cap is now one wave across the worker concurrency, as
the --max-parallel-chunks docs say; 16 remains when the concurrency is
unknown.

* feat(cli): remove a stack's reserved concurrency with --concurrency=none

Since an omitted --concurrency now keeps the stack's reservation, there
was no CLI way back to the unreserved default. --concurrency=none sends
ReservedConcurrency=-1, the state file records the stack as unreserved
and deploy says the reservation was removed. Positive N and an omitted
flag behave as before; any other value is rejected instead of being
silently ignored.

* chore(aws-lambda): raise the package size budget for account-sized concurrency

Measured with pnpm@10.17.1 pack after rebasing on main with the S3 assembly change: 67,763 packed / 244,685 unpacked; the budget is the check's own 5% headroom over that.
2026-10-19 00:57:30 +00:00
James Russo 17a2a00ed5 feat(cloud): default distributed plans to v2 (#3311)
* feat(cloud): default distributed plans to v2

* fix(cloud): address plan v2 review feedback

* fix(examples): document explicit v2 samples
2026-08-17 17:24:31 -04:00
James Russo 5bf61d6df0 feat(aws-lambda): support plan protocol v2 (#2789)
* feat(aws-lambda): support plan protocol v2

* fix(aws-lambda): align SAM v2 terminal errors
2026-07-25 23:42:51 -04:00
James Russo aa58ebc048 feat(lambda): add real-AWS smoke + benchmark script (#908)
* feat(lambda): add real-AWS smoke + benchmark script

Phase 6.3 of the distributed rendering plan
(DISTRIBUTED-RENDERING-PLAN.md §11 Phase 6a). Local bash script that
deploys the PR 6.2 SAM template to your own AWS account, renders a
fixture composition through the Step Functions state machine at several
chunk counts, PSNR-compares each output against the in-process
baseline, and tears the stack down.

This is the gate that proves the architecture works on real Lambda
infrastructure. After it runs green and the numbers are good, Phase 6b
(CLI, CDK, docs) can proceed with confidence.

Script lives at examples/aws-lambda/scripts/smoke.sh. Defaults:
  - fixture:        mp4-h264-sdr
  - chunk_counts:   2,4,8
  - psnr-threshold: 50 dB
  - region:         us-east-1
  - stack-name:     hyperframes-lambda-smoke-<timestamp>

AWS credentials come from the standard resolution chain (env vars,
~/.aws/credentials, SSO, IMDS). Pin a specific profile via --profile or
AWS_PROFILE; the script doesn't ship a default.

Workflow:
  1. Pre-flight: verify aws/sam/bun/ffmpeg/jq/zip on PATH; check
     credentials via sts:GetCallerIdentity.
  2. Build the PR 6.1 ZIP and run verify:zip-size.
  3. sam validate --lint + sam deploy under a per-run stack name.
  4. Zip the fixture's src/ and upload to the render bucket.
  5. For each chunk count, start a Step Functions execution, poll for
     completion (25-min cap), download the output mp4 and the execution
     history JSON, ffmpeg-psnr against the LFS-tracked in-process
     baseline, and append to results.json.
  6. Gate on the PSNR threshold.
  7. Empty the bucket + sam delete (unless --keep-stack).

Outputs land under ./lambda-smoke-artifacts/:
  - results.json (chunkCount x wallClockMs x psnrAvgDb)
  - renders/N<N>-output.mp4
  - renders/N<N>-history.json (full Step Functions execution history)

Per-run stack name with concurrency-safe AWS resource isolation. Run
multiple smokes in parallel without races; teardown guards against
stale stacks via cleanup_and_exit on every failure path.

Distinction from CI: this is a maintainer-run gate, not part of regular
CI. The architecture's per-PR safety net is the local Docker-based
BeginFrame probe (PR 6.1) and the upcoming Lambda RIE smoke mode (PR
6.6). No GitHub Actions / OIDC / cross-account secrets required.

This is part of the 8-PR Phase 6 stack; PR 6.3 of 8 — the last PR of
Phase 6a (validation). Phase 6b (CLI + CDK + docs) starts once 6.3's
benchmark numbers come back.

* fix(lambda): address PR 880 review feedback

- Document wall-clock methodology bias inline (eval.sh header + README):
  local timing includes bun + tsx + harness scaffolding while Lambda
  timing measures pure SFN execution, so "speedup" is end-to-end CLI
  experience, not renderer-vs-renderer.
- Add --iterations N (default 1) with median wall-clock reporting via
  awk-side median. Cold-start variance is ±5-10s per chunk; single-
  sample readings made the PR-body speedup table not ground truth.
- Add --reserved-concurrency flag to both scripts; default still 16 but
  no longer hardcoded. Pass-through to ReservedConcurrency CFN param.
- README: cost-per-pass estimate for both scripts.
- Replace `sed -n '2,30p' "$0"` help with usage() heredoc in both
  scripts — fragile to header reflows and didn't survive the comment
  expansion this commit adds anyway.
- eval.sh RMS-level parser: add a third fallback (`RMS level:` with no
  `dB` suffix) for older ffmpeg builds where astats predates the unit
  tag. Word-boundary guards keep `RMS peak level` from being eaten.

* docs(lambda): drop internal plan-doc + Rio refs from smoke/eval scripts
2026-05-16 18:41:30 -04:00