Skip to content

Conversation

@pranaygp
Copy link
Collaborator

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.5 [email protected]

@changeset-bot
Copy link

changeset-bot bot commented Dec 18, 2025

🦋 Changeset detected

Latest commit: 32f21aa

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 16 packages
Name Type
@workflow/core Patch
@workflow/world Patch
@workflow/world-local Patch
@workflow/world-postgres Patch
@workflow/world-vercel Patch
@workflow/builders Patch
@workflow/cli Patch
@workflow/next Patch
@workflow/nitro Patch
@workflow/web-shared Patch
workflow Patch
@workflow/world-testing Patch
@workflow/astro Patch
@workflow/sveltekit Patch
@workflow/nuxt Patch
@workflow/ai Patch

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

@vercel
Copy link
Contributor

vercel bot commented Dec 18, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
example-nextjs-workflow-turbopack Error Error Dec 24, 2025 4:20am
example-nextjs-workflow-webpack Error Error Dec 24, 2025 4:20am
example-workflow Error Error Dec 24, 2025 4:20am
workbench-astro-workflow Error Error Dec 24, 2025 4:20am
workbench-express-workflow Error Error Dec 24, 2025 4:20am
workbench-fastify-workflow Error Error Dec 24, 2025 4:20am
workbench-hono-workflow Error Error Dec 24, 2025 4:20am
workbench-nitro-workflow Error Error Dec 24, 2025 4:20am
workbench-nuxt-workflow Error Error Dec 24, 2025 4:20am
workbench-sveltekit-workflow Error Error Dec 24, 2025 4:20am
workbench-vite-workflow Error Error Dec 24, 2025 4:20am
workflow-docs Error Error Dec 24, 2025 4:20am

@github-actions
Copy link
Contributor

github-actions bot commented Dec 18, 2025

🧪 E2E Test Results

No test result files found.


Some E2E test jobs failed:

  • Vercel Prod: failure
  • Local Dev: failure
  • Local Prod: failure
  • Local Postgres: failure
  • Windows: failure

Check the workflow run for details.

Copy link
Collaborator Author

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@pranaygp pranaygp changed the base branch from pranaygp/perf-phase-3b-atomic-events to graphite-base/641 December 18, 2025 03:51
@pranaygp pranaygp force-pushed the pranaygp/perf-batch-events branch from 853963d to 752bc6b Compare December 18, 2025 04:07
@pranaygp pranaygp changed the base branch from graphite-base/641 to pranaygp/perf-phase-3b-atomic-events December 18, 2025 04:07
Copy link
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔧 Build Fix:

The CreateEventRequest type is used in the createWorkflowRunEventBatch function but is not imported from the @workflow/world package. This causes a TypeScript compilation error because the type is undefined in this file.

Fix on Vercel

@pranaygp pranaygp changed the base branch from pranaygp/perf-phase-3b-atomic-events to graphite-base/641 December 23, 2025 04:58
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@pranaygp pranaygp force-pushed the pranaygp/perf-batch-events branch from f15434b to 32f21aa Compare December 24, 2025 04:19
@pranaygp pranaygp changed the base branch from graphite-base/641 to pranaygp/perf-phase-3b-atomic-events December 24, 2025 04:20
Comment on lines +766 to +841
// Update run status for run_completed events
if (runCompletedEvents.length > 0) {
const completedData = (runCompletedEvents[0] as any).eventData as {
output?: any;
};
await drizzle
.update(Schema.runs)
.set({
status: 'completed',
output: completedData.output as SerializedContent | undefined,
completedAt: now,
updatedAt: now,
})
.where(eq(Schema.runs.runId, effectiveRunId));
}

// Update run status for run_failed events
if (runFailedEvents.length > 0) {
const failedData = (runFailedEvents[0] as any).eventData as {
error: any;
errorCode?: string;
};
const errorMessage =
typeof failedData.error === 'string'
? failedData.error
: (failedData.error?.message ?? 'Unknown error');
// Store structured error as JSON for deserializeRunError to parse
const errorJson = JSON.stringify({
message: errorMessage,
stack: failedData.error?.stack,
code: failedData.errorCode,
});
await drizzle
.update(Schema.runs)
.set({
status: 'failed',
error: errorJson,
completedAt: now,
updatedAt: now,
})
.where(eq(Schema.runs.runId, effectiveRunId));
}

// Update run status for run_cancelled events
if (runCancelledEvents.length > 0) {
await drizzle
.update(Schema.runs)
.set({
status: 'cancelled',
completedAt: now,
updatedAt: now,
})
.where(eq(Schema.runs.runId, effectiveRunId));
}

// Update run status for run_paused events
if (runPausedEvents.length > 0) {
await drizzle
.update(Schema.runs)
.set({
status: 'paused',
updatedAt: now,
})
.where(eq(Schema.runs.runId, effectiveRunId));
}

// Update run status for run_resumed events
if (runResumedEvents.length > 0) {
await drizzle
.update(Schema.runs)
.set({
status: 'running',
updatedAt: now,
})
.where(eq(Schema.runs.runId, effectiveRunId));
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The createBatch method is missing the hook cleanup logic that the create method performs when processing terminal run events (run_completed, run_failed, run_cancelled). This causes inconsistent behavior and prevents hook tokens from being reused.

View Details
📝 Patch Details
diff --git a/packages/world-postgres/src/storage.ts b/packages/world-postgres/src/storage.ts
index 4d56f53..2075c10 100644
--- a/packages/world-postgres/src/storage.ts
+++ b/packages/world-postgres/src/storage.ts
@@ -777,6 +777,10 @@ export function createEventsStorage(drizzle: Drizzle): Storage['events'] {
             updatedAt: now,
           })
           .where(eq(Schema.runs.runId, effectiveRunId));
+        // Delete all hooks for this run to allow token reuse
+        await drizzle
+          .delete(Schema.hooks)
+          .where(eq(Schema.hooks.runId, effectiveRunId));
       }
 
       // Update run status for run_failed events
@@ -804,6 +808,10 @@ export function createEventsStorage(drizzle: Drizzle): Storage['events'] {
             updatedAt: now,
           })
           .where(eq(Schema.runs.runId, effectiveRunId));
+        // Delete all hooks for this run to allow token reuse
+        await drizzle
+          .delete(Schema.hooks)
+          .where(eq(Schema.hooks.runId, effectiveRunId));
       }
 
       // Update run status for run_cancelled events
@@ -816,6 +824,10 @@ export function createEventsStorage(drizzle: Drizzle): Storage['events'] {
             updatedAt: now,
           })
           .where(eq(Schema.runs.runId, effectiveRunId));
+        // Delete all hooks for this run to allow token reuse
+        await drizzle
+          .delete(Schema.hooks)
+          .where(eq(Schema.hooks.runId, effectiveRunId));
       }
 
       // Update run status for run_paused events

Analysis

Missing hook cleanup in createBatch() for terminal run events

What fails: The createBatch() method in packages/world-postgres/src/storage.ts fails to delete hooks when processing terminal run events (run_completed, run_failed, run_cancelled), unlike the create() method which properly cleans up hooks. This causes hook tokens to never be released for reuse, leading to potential token exhaustion in systems processing many workflow runs.

How to reproduce:

  1. Call createBatch() with events including a hook_created event
  2. Process a batch with a terminal event (run_completed, run_failed, or run_cancelled)
  3. Check the database hooks table - hooks will still exist for that run
  4. Attempt to create and complete another workflow run with the same hook token
  5. Observe that the old hooks are not cleaned up, preventing token reuse

Result: The hooks table retains entries for completed runs indefinitely. Comparing to the create() method behavior at lines 416-419, 451-454, and 471-474, these hooks should be deleted after status updates, but are not in createBatch().

Expected: Both create() and createBatch() should consistently delete hooks when terminal run events occur (lines 766-841 in createBatch should include hook deletion after each terminal status update, matching the pattern in create()).

Root cause: Missing drizzle.delete(Schema.hooks).where(eq(Schema.hooks.runId, effectiveRunId)) statements after the runCompletedEvents, runFailedEvents, and runCancelledEvents status update blocks in createBatch().

Implementation note: Added hook deletion logic to match the exact pattern used in the create() method, ensuring consistent behavior across both APIs and allowing hook tokens to be reused for future workflow runs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants