c50f59a53b
* feat(lambda): add Lambda handler, ZIP bundling, and BeginFrame probe
Phase 6 of the distributed rendering plan: AWS Lambda turnkey adoption
(see DISTRIBUTED-RENDERING-PLAN.md §11 Phase 6 + §15).
This PR adds the new packages/aws-lambda/ workspace package that wraps
the OSS plan/renderChunk/assemble primitives in an AWS Lambda handler,
plus a build pipeline that bundles the handler + Chromium runtime +
ffmpeg into a deployable ZIP.
Architecture: ZIP deploy (not Docker image), Chrome via @sparticuz/chromium
with chrome-headless-shell fallback, dispatch on event.Action ∈ {plan,
renderChunk, assemble}.
The load-bearing concern — does @sparticuz/chromium's chrome-headless-shell
build honour CDP HeadlessExperimental.beginFrame? — is pinned by the new
scripts/probe-beginframe.ts regression guard. Probe boots the runtime
inside public.ecr.aws/lambda/nodejs:22, navigates to a static page, and
asserts beginFrame returns a PNG buffer. Verified locally + inside the
Docker container; both pass with hasDamage=true.
Sizes (sparticuz source): unzipped 157 MiB, zipped 99 MiB. Well under
the 240 MiB / 150 MiB in-house gates and the Lambda 250 MiB hard ceiling.
This is part of a stack of 8 PRs (3 in Phase 6a, 5 in Phase 6b); this is
PR 6.1.
* fix(lambda): address PR 878 review feedback
- Verify event.PlanHash against the untarred plan.json at the handler
boundary before invoking the producer primitive. Throws typed
PLAN_HASH_MISMATCH on divergence so Step Functions routes it as
non-retryable; previously the field was schema bloat the handler
ignored, leaving enforcement entirely inside the producer.
- Standardize on MiB throughout build-zip.ts, verify-zip-size.ts, and
the README. Lambda's hard ceiling is 250 MiB (AWS docs label "250 MB"
but use binary mebibytes); previously mixed units made the 248 MiB
budget look like a ~5 MB margin instead of the 2 MiB it actually is.
- stageChromeHeadlessShell now picks Chrome versions via numeric semver
comparison instead of lexicographic sort+reverse — the latter would
silently pick "99.x" over "131.x" once Chrome cached three-digit
majors that aren't width-aligned.
- Drop _setSparticuzChromiumForTests from the public index barrel.
Test-only DI seam imported directly from ./chromium.js in tests.
- Replace require("node:fs") inside walkSize() with the top-level fs
imports — file is ESM and the same module is already imported.
* docs(lambda): drop internal plan-doc refs from package README
* ci(windows): fix bun filter UNION bug excluding producer from Windows tests
`bun run --filter "!a" --filter "!b" test` composes as a UNION (any
package matching either negation runs), not an intersection. Effect:
@hyperframes/producer was still being tested on Windows even though
it's explicitly excluded — its regression harness (Docker + LFS golden
mp4 baselines) is Linux-only and was driving the 32min timeout.
Enumerate the packages we DO want to test instead.
62 lines
2.0 KiB
Docker
62 lines
2.0 KiB
Docker
# BeginFrame regression-guard container.
|
|
#
|
|
# Uses the official AWS Lambda Node 22 image as the base so the probe
|
|
# exercises @sparticuz/chromium against the SAME glibc, kernel feature
|
|
# set, and `/tmp` filesystem layout that real Lambda invocations see. If
|
|
# this Dockerfile passes, the bundled handler is on solid footing for
|
|
# real AWS.
|
|
#
|
|
# Build context: monorepo root (../../). Build + run:
|
|
#
|
|
# bun run --cwd packages/aws-lambda probe:beginframe:docker
|
|
#
|
|
# The default CMD runs `tsx scripts/probe-beginframe.ts` and exits 0 on
|
|
# pass, 1 on BeginFrame failure, 2 on harness failure.
|
|
|
|
FROM public.ecr.aws/lambda/nodejs:22
|
|
|
|
# Shared libraries @sparticuz/chromium expects but the Lambda base image
|
|
# does not bring in by default. Versions are pinned to whatever
|
|
# `dnf install` resolves on the Lambda base image at build time; we just
|
|
# need them present.
|
|
RUN dnf install -y \
|
|
alsa-lib \
|
|
atk \
|
|
cups-libs \
|
|
gtk3 \
|
|
libdrm \
|
|
libxkbcommon \
|
|
libXcomposite \
|
|
libXdamage \
|
|
libXrandr \
|
|
mesa-libgbm \
|
|
nss \
|
|
pango \
|
|
tar \
|
|
gzip \
|
|
unzip \
|
|
&& dnf clean all
|
|
|
|
WORKDIR /var/task
|
|
|
|
# The probe is self-contained — we install the three deps it needs into a
|
|
# fresh package directory rather than re-using the monorepo's
|
|
# workspace-rooted manifests (which carry `workspace:` protocol deps npm
|
|
# can't resolve).
|
|
COPY packages/aws-lambda/scripts/ scripts/
|
|
|
|
RUN printf '{"name":"hf-lambda-probe","version":"1.0.0","type":"module"}\n' > package.json \
|
|
&& npm install --no-audit --no-fund --omit=optional \
|
|
@sparticuz/chromium@148.0.0 \
|
|
puppeteer-core@^24.39.1 \
|
|
tsx@^4.21.0
|
|
|
|
ENV NODE_PATH=/var/task/node_modules
|
|
ENV PATH="/var/task/node_modules/.bin:${PATH}"
|
|
|
|
# Lambda's `tmpfs` is mounted at /tmp; sparticuz decompresses into /tmp
|
|
# at runtime. The base image already has /tmp writable.
|
|
|
|
ENTRYPOINT []
|
|
CMD ["node", "--experimental-strip-types", "scripts/probe-beginframe.ts"]
|