Repository navigation
@remotion/web-renderer: release completed render results from queues - #12631
JonnyBurger merged 2 commits into
Conversation
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Still queue completion tail —
render-still-on-web.tsxreturns the original render promise to callers and stores a completion-only tail (render.then(() => {}, () => {})) inonlyOneStillRenderAtATimeQueue. - Media queue completion tail — the same ownership change applied to
onlyOneMediaRenderAtATimeQueueinrender-media-on-web.tsx. - Queue typing —
render-operations-queue.tsdrops theas Promise<unknown>casts sorefinfersPromise<void>; the return casts are no longer needed. - Tests —
cancel-render.test.tsxasserts a rejected render leaves anundefined-resolving queue tail while preserving the original error identity; newrender-queue-result.test.tsxcovers successful still/media renders, tail settling toundefined, and caller results remaining usable after a subsequent queued render.
Verified locally: ESLint clean (only the two pre-existing TODO warnings in render-media-on-web.tsx), oxfmt --check passes, and tsc --noEmit passes. A spec- and V8-backed check confirmed serialization is preserved (two synchronous calls still run strictly end-to-end), the queue no longer retains the settled still result/canvas/internalState, and caller result/rejection identities are intact.
ℹ️ The completion tail also marks the returned promise as handled, silencing ignored render failures
The internal render.then(() => {}, () => {}) attaches a rejection handler to the same promise returned to callers, so a caller that ignores a failing render (and queues no further render) will no longer trigger an unhandledrejection event — the base code surfaced it because queue.ref and the returned promise carried no handler. Callers that await or .catch() the result are unaffected. This is inherent to observing completion from the queue (any observer marks the source handled), so it is likely an acceptable trade-off; raising it only because the PR body states rejection identities stay intact without noting the change in global surfacing.
Technical details
# Completion tail suppresses unhandledrejection for ignored renders
## Affected sites
- `packages/web-renderer/src/render-still-on-web.tsx:285` — the tail attaches a rejection handler to the promise returned at line 290.
- `packages/web-renderer/src/render-media-on-web.tsx:900` — same for the promise returned at line 905.
## Required outcome
- None required. Preserving global surfacing would mean not attaching a handler to the returned promise, which conflicts with tracking completion, so this is effectively a design trade-off.
## References
- `Promise.then` marks the source promise as handled when a rejection handler is present (`HostPromiseRejectionTracker`): https://tc39.es/ecma262/multipage/control-abstraction-objects.html#sec-host-promise-rejection-tracker
- `unhandledrejection` fires only for promises with no rejection handler: https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_eventdeepseek-v4.1-flash | 𝕏
# Conflicts: # packages/web-renderer/src/render-still-on-web.tsx
@remotion/web-renderer: release completed render results from queues
|
Thanks a lot! |

The module-global still and media queues store the actual render promise. Once settled, that promise keeps its last result or rejection reason alive until another render replaces it. A still result includes its canvas and internal renderer state, so an idle queue can unnecessarily keep those resources reachable after the caller is done.
Keep a completion-only tail in each existing queue and return the original render promise to callers. The tail resolves to
undefinedon both success and failure; caller results and rejection identities remain intact. The queue types now inferPromise<void>, and the result casts are no longer needed. No public API changes.Validation
bun run makewebrenderer: all 13 workspace build tasks pass, including TypeScript and production bundles.bunx vitest run src/test/render-queue-result.test.tsx src/test/cancel-render.test.tsx --browser chromium: 3 tests pass using real still and media renders. They check that queue tails contain no completed payload, results remain usable after a subsequent queued render, and the original cancellation error is preserved.render-media-on-web.tsx.Why each file changes
packages/web-renderer/src/render-still-on-web.tsxrender-media-on-web.tsxrender-operations-queue.tstest/cancel-render.test.tsxtest/render-queue-result.test.tsxDiff cleanup found no formatting-only changes, parallel mechanisms or unused exports.