Repository navigation
perf(core): load workflows lazily from the generated entrypoint - #476
Merged
Merged
Conversation
This comment was marked as outdated.
This comment was marked as outdated.
A static re-export of every workflow makes each cached workflow evaluate the whole catalog in Temporal's reusable VM. Each workflow export is now an async wrapper that dynamic-imports its module in eager mode (same bundle); the catalog workflow stays static. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
szanata
force-pushed
the
perf/lazy-workflow-entrypoint
branch
from
October 30, 2026 20:44
02b3c9b to
d2672e2
Compare
This comment was marked as outdated.
This comment was marked as outdated.
Contributor
PR reviewVerdict✅ PASS FindingsNone. Categories
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The generated workflow entrypoint statically re-exports every workflow (
export { default as X } from 'P';). Temporal's reusable VM caches modules loaded during an activation in that workflow's ownmoduleCache, so every cached workflow evaluates the whole catalog.Mechanism
@temporalio/worker/lib/workflow/reusable-vm.js:138-156:__webpack_module_cache__is a Proxy. Asetbefore any activator exists goes into the sharedsharedModulesmap; asetduring an activation goes into that workflow'smoduleCache(lines 150-156). A static entrypoint is evaluated inside each activation, so each cached workflow holds its own copy of every workflow module.Change
Each user workflow and alias export in the entrypoint becomes an async wrapper that does
await import( /* webpackMode: "eager" */ 'P' )and calls the default export. Eager mode keeps everything in one bundle.$catalogstays a static export. Workflow type resolution is by export name, which is unchanged. The framework reads workflow metadata (METADATA_ACCESS_SYMBOL) only in Node (importComponentsin the loader and the catalog), never from the bundle, so the wrapper loses nothing.--checkbundles the same entrypoint throughbundleWorkflowCode; a one-workflow lazy entrypoint bundled successfully with that call.Measurements
Measured 2026-10-19 on a GrowthX os-workflows worker (@outputai/core 0.13.0, Temporal TS SDK 1.20.3,
reuseV8Contextdefault true, macOS footprint, workflows parked in sleep). The lazy rows come from patching the same shape by hand in node_modules.Prod pods reached 7-8 GB at 25 cached workflows and the fleet autoscaled to its 20-pod max.
bundlerOptions.preloadModulesdid not help; preloading@outputai/corebreaks activations ("Cannot assign to read only property 'lastIndex' of object '[object RegExp]'"). With the hand patch, a parked workflow and a real workflow with 5 activities and 3 nested child workflows completed across forced worker restarts with zero nondeterminism or module errors.Follow-up local A/B benchmark
Repeated 2026-10-30 after rebasing against
main, using Node 24.15.0, Temporal TS SDK 1.24.0,reuseV8Context: true, and the 72-workflowtest_workflowscatalog. Each variant started from a stopped Compose environment. Memory values are medians of threedocker statssamples before and after starting 100 uniquesleepworkflows parked on their first timer. Worker telemetry confirmed 101 cached workflows, including the catalog, with no in-flight work.This smaller catalog produces smaller absolute savings than the production catalog, but independently confirms the same effect on the current Temporal SDK and rebased implementation.
Not tested: restart during an in-flight activity; a prod-sized mixed cache.
🤖 Generated with Claude Code