-
Notifications
You must be signed in to change notification settings - Fork 188
Make serialization functions async #978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 7f8582e The changes in this PR will be included in the next version bump. This PR includes changesets to release 15 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
🧪 E2E Test Results❌ Some tests failed Summary
❌ Failed Tests🌍 Community Worlds (41 failed)turso (41 failed):
Details by Category✅ ▲ Vercel Production
✅ 💻 Local Development
✅ 📦 Local Production
✅ 🐘 Local Postgres
✅ 🪟 Windows
❌ 🌍 Community Worlds
✅ 📋 Other
|
📊 Benchmark Results
workflow with no steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) workflow with 1 step💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Nitro | Next.js (Turbopack) workflow with 10 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) | Nitro workflow with 25 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) workflow with 50 sequential steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) | Nitro Promise.all with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Nitro | Express Promise.all with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) Promise.all with 50 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Next.js (Turbopack) | Express | Nitro Promise.race with 10 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Express | Next.js (Turbopack) Promise.race with 25 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Next.js (Turbopack) | Express Promise.race with 50 concurrent steps💻 Local Development
▲ Production (Vercel)
🔍 Observability: Nitro | Next.js (Turbopack) | Express Stream Benchmarks (includes TTFB metrics)workflow with stream💻 Local Development
▲ Production (Vercel)
🔍 Observability: Express | Next.js (Turbopack) | Nitro SummaryFastest Framework by WorldWinner determined by most benchmark wins
Fastest World by FrameworkWinner determined by most benchmark wins
Column Definitions
Worlds:
|
This stack of pull requests is managed by Graphite. Learn more about stacking. |
pranaygp
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review: PR #978 - Make serialization functions async
Summary: Clean mechanical refactor that makes all 8 dehydrate/hydrate functions async. This is well-structured as a standalone PR since it's a pure no-op refactor -- the function bodies remain synchronous, only signatures and call sites are updated.
Strengths:
- Good separation of concerns -- this refactor is isolated from the actual encryption logic
- All callers are properly updated with
await/Promise.all - The changeset correctly lists all affected packages
- The
Promise.racetest assertion relaxation is reasonable given async microtask timing changes
Questions/Concerns:
-
Performance consideration: In
step.tsandhook.ts, the callers that were previously synchronous callbacks now use.then()/.catch()patterns. This is the right approach since you can't useawaitin the resolve callback of a Promise constructor, but worth noting that this adds microtask overhead on every step completion during replay. For workflows with hundreds of steps, this could add up. Not a blocker, just something to be aware of. -
Changeset scope: The changeset includes
@workflow/world-testingbut I don't see material changes to that package's public API in this diff -- it's just updating test utilities. Consider whether this really warrants a published changeset entry for that package, or if it's just an internal change.
Overall this is a clean, well-scoped PR. Looks good to land.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Refactors the core serialization “dehydrate/hydrate” API surface to be async, returning Promise<...>, and updates runtime/CLI/web/test call sites to await (or use Promise.all / .then() where needed). This enables future async-only transforms (e.g., encrypt/decrypt) without another broad signature change.
Changes:
- Make 8 core serialization functions in
packages/core/src/serialization.tsasync and update their return types toPromise<...>. - Update callers across runtime, observability, CLI, and web server actions to
awaithydration/dehydration (including batching withPromise.all). - Update tests for async serialization/hydration and relax a
Promise.raceordering assertion.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/core/src/serialization.ts | Converts core (de)serialization APIs to async/Promise return types. |
| packages/core/src/workflow.ts | Awaits workflow argument hydration and return value dehydration. |
| packages/core/src/step.ts | Adjusts step result hydration to async .then/.catch resolution. |
| packages/core/src/workflow/hook.ts | Adjusts hook payload hydration to async .then/.catch resolution. |
| packages/core/src/runtime/start.ts | Awaits workflow argument dehydration before emitting run_created. |
| packages/core/src/runtime/run.ts | Awaits workflow return value hydration for completed runs. |
| packages/core/src/runtime/runs.ts | Awaits workflow argument hydration when recreating runs. |
| packages/core/src/runtime/step-handler.ts | Awaits step argument hydration and step return value dehydration. |
| packages/core/src/runtime/suspension-handler.ts | Awaits dehydration when building hook/step events; uses Promise.all for hook events. |
| packages/core/src/runtime/resume-hook.ts | Awaits hook metadata hydration and payload dehydration. |
| packages/core/src/observability.ts | Makes hydrateResourceIO and helpers async; awaits internal hydration paths. |
| packages/cli/src/lib/inspect/output.ts | Awaits hydrateResourceIO and batches hydration with Promise.all. |
| packages/web/src/server/workflow-server-actions.ts | Makes hydration helper async and batches list hydration via Promise.all. |
| workbench/nextjs-webpack/pages/api/trigger-pages.ts | Awaits workflow argument hydration from request body. |
| workbench/nextjs-turbopack/pages/api/trigger-pages.ts | Awaits workflow argument hydration from request body. |
| packages/core/src/serialization.test.ts | Updates serialization tests to async/await and promise rejection assertions. |
| packages/core/src/workflow.test.ts | Updates workflow tests for async serde and relaxes Promise.race ordering assertion. |
| packages/core/src/step.test.ts | Updates step tests for async dehydration. |
| packages/core/src/workflow/hook.test.ts | Updates hook tests for async dehydration. |
| packages/core/src/observability.test.ts | Updates observability tests for async hydration/dehydration. |
| .changeset/async-serde.md | Publishes a patch changeset documenting async serialization refactor. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
814d64c to
702c96d
Compare
702c96d to
7f8582e
Compare

Summary
Makes all 8 dehydrate/hydrate serialization functions async, returning
Promise<...>instead of synchronous values. This is a prerequisite for E2E encryption where encrypt/decrypt operations are inherently asynchronous.This is a no-op refactor — the function bodies remain synchronous, only the signatures and call sites are updated.
Changes
asynckeyword to all 8 serialization functions inserialization.tsPromise<Uint8Array | unknown>return types where neededawaitstep.ts,hook.ts), use.then()/.catch()patternhydrateResourceIOand its internal helpers inobservability.tsasyncinspect/output.ts) and web (workflow-server-actions.ts) callers withawait/Promise.allPromise.raceordering test assertion (microtask timing changes with async hydration)Files changed (21)
Core serialization:
serialization.ts(signatures only)Runtime callers:
start.ts,workflow.ts,step.ts,hook.ts,step-handler.ts,suspension-handler.ts,resume-hook.ts,run.ts,runs.tsObservability:
observability.tsCLI/Web:
inspect/output.ts,workflow-server-actions.tsWorkbenches:
trigger-pages.ts(2 files)Tests:
serialization.test.ts,workflow.test.ts,step.test.ts,hook.test.ts,observability.test.tsTest plan
All 305 core tests pass. Build succeeds.