From 80272d7d163120c56f978567da97c180920838eb Mon Sep 17 00:00:00 2001 From: Ian Macartney <366683+ianmacartney@users.noreply.github.com> Date: Tue, 14 Apr 2026 20:08:05 -0700 Subject: [PATCH 01/10] fail steps with oversized return values instead of getting stuck When a step returns a value >1MB, the db.replace call fails and the workflow gets stuck with the step permanently in progress. Instead, check the size and mark the step as failed with a truncated preview of the data (128KB prefix + suffix). Co-Authored-By: Claude Opus 4.6 --- src/component/event.ts | 13 +++++++++-- src/component/oversizedValues.ts | 40 ++++++++++++++++++++++++++++++++ src/component/pool.ts | 25 +++++--------------- 3 files changed, 57 insertions(+), 21 deletions(-) create mode 100644 src/component/oversizedValues.ts diff --git a/src/component/event.ts b/src/component/event.ts index a002316c..779b2d56 100644 --- a/src/component/event.ts +++ b/src/component/event.ts @@ -6,6 +6,7 @@ import { vResultValidator } from "@convex-dev/workpool"; import type { Doc, Id } from "./_generated/dataModel.js"; import { assert } from "convex-helpers"; import { enqueueWorkflow, getWorkpool, workpoolOptions } from "./pool.js"; +import { checkForOversizedResult } from "./oversizedValues.js"; export async function awaitEvent( ctx: MutationCtx, @@ -40,7 +41,11 @@ export async function awaitEvent( stepId: entry._id, }, }); - entry.step.runResult = event.state.result; + entry.step.runResult = await checkForOversizedResult( + ctx, + event.state.result, + { stepId: entry._id }, + ); entry.step.inProgress = false; entry.step.completedAt = Date.now(); break; @@ -146,7 +151,11 @@ export const send = mutation({ ); assert(step.step.kind === "event", "Step is not an event"); step.step.eventId = event._id; - step.step.runResult = args.result; + step.step.runResult = await checkForOversizedResult( + ctx, + args.result, + { stepId: step._id }, + ); step.step.inProgress = false; step.step.completedAt = Date.now(); await ctx.db.replace(step._id, step); diff --git a/src/component/oversizedValues.ts b/src/component/oversizedValues.ts new file mode 100644 index 00000000..cb066beb --- /dev/null +++ b/src/component/oversizedValues.ts @@ -0,0 +1,40 @@ +import { type Value, convexToJson, getConvexSize } from "convex/values"; +import type { RunResult } from "@convex-dev/workpool"; +import type { MutationCtx } from "./_generated/server.js"; +import type { Id } from "./_generated/dataModel.js"; + +export const MAX_RETURN_VALUE_SIZE = 1 << 20; // 1 MB +const PREVIEW_SIZE = 128 << 10; // 128 KB + +function truncatedPreview(returnValue: unknown): string { + const json = JSON.stringify(convexToJson(returnValue as Value)); + if (json.length <= PREVIEW_SIZE * 2) { + return json; + } + return json.slice(0, PREVIEW_SIZE) + "..." + json.slice(-PREVIEW_SIZE); +} + +export function checkReturnValueSize(returnValue: unknown): string | null { + const size = getConvexSize(returnValue as Value | undefined); + if (size > MAX_RETURN_VALUE_SIZE) { + return `Step return value too large (${size} bytes). Maximum is ${MAX_RETURN_VALUE_SIZE} bytes. Preview: ${truncatedPreview(returnValue)}`; + } + return null; +} + +export async function checkForOversizedResult( + _ctx: MutationCtx, + result: RunResult, + _opts: { + stepId: Id<"steps">; + }, +): Promise { + if (result.kind !== "success") { + return result; + } + const sizeError = checkReturnValueSize(result.returnValue); + if (!sizeError) { + return result; + } + return { kind: "failed", error: sizeError }; +} diff --git a/src/component/pool.ts b/src/component/pool.ts index cdaf82fb..862452cb 100644 --- a/src/component/pool.ts +++ b/src/component/pool.ts @@ -22,6 +22,7 @@ import { getDefaultLogger } from "./utils.js"; import { completeHandler } from "./workflow.js"; import type { Doc } from "./_generated/dataModel.js"; import { vWorkflowId, type WorkflowId } from "../types.js"; +import { checkForOversizedResult } from "./oversizedValues.js"; export const workpoolOptions = v.object({ logLevel: v.optional(logLevel), @@ -147,25 +148,11 @@ async function onCompleteHandler( } journalEntry.step.inProgress = false; journalEntry.step.completedAt = Date.now(); - switch (args.result.kind) { - case "success": - journalEntry.step.runResult = { - kind: "success", - returnValue: args.result.returnValue, - }; - break; - case "failed": - journalEntry.step.runResult = { - kind: "failed", - error: args.result.error, - }; - break; - case "canceled": - journalEntry.step.runResult = { - kind: "canceled", - }; - break; - } + journalEntry.step.runResult = await checkForOversizedResult( + ctx, + args.result, + { stepId }, + ); await ctx.db.replace(journalEntry._id, journalEntry); console.debug(`Completed execution of ${stepId}`, journalEntry); From 4ae172add0e98ca9e867ec2f3a517ead64840be2 Mon Sep 17 00:00:00 2001 From: Ian Macartney <366683+ianmacartney@users.noreply.github.com> Date: Tue, 14 Apr 2026 22:42:00 -0700 Subject: [PATCH 02/10] save above 800KB --- src/component/oversizedValues.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/component/oversizedValues.ts b/src/component/oversizedValues.ts index cb066beb..d2728b06 100644 --- a/src/component/oversizedValues.ts +++ b/src/component/oversizedValues.ts @@ -3,7 +3,7 @@ import type { RunResult } from "@convex-dev/workpool"; import type { MutationCtx } from "./_generated/server.js"; import type { Id } from "./_generated/dataModel.js"; -export const MAX_RETURN_VALUE_SIZE = 1 << 20; // 1 MB +export const MAX_RETURN_VALUE_SIZE = 800 << 10; // 800 KiB const PREVIEW_SIZE = 128 << 10; // 128 KB function truncatedPreview(returnValue: unknown): string { From 953687fbb0cead8b8612cbeed2e7b84b7f9f59cc Mon Sep 17 00:00:00 2001 From: Ian Macartney <366683+ianmacartney@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:15:19 -0700 Subject: [PATCH 03/10] type --- src/component/oversizedValues.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/component/oversizedValues.ts b/src/component/oversizedValues.ts index d2728b06..9502485c 100644 --- a/src/component/oversizedValues.ts +++ b/src/component/oversizedValues.ts @@ -14,8 +14,10 @@ function truncatedPreview(returnValue: unknown): string { return json.slice(0, PREVIEW_SIZE) + "..." + json.slice(-PREVIEW_SIZE); } -export function checkReturnValueSize(returnValue: unknown): string | null { - const size = getConvexSize(returnValue as Value | undefined); +export function checkReturnValueSize( + returnValue: Value | undefined, +): string | null { + const size = getConvexSize(returnValue); if (size > MAX_RETURN_VALUE_SIZE) { return `Step return value too large (${size} bytes). Maximum is ${MAX_RETURN_VALUE_SIZE} bytes. Preview: ${truncatedPreview(returnValue)}`; } From 93149bdd1aa63ed6aeb308a0cb6ff2820a1dc5e0 Mon Sep 17 00:00:00 2001 From: Ian Macartney <366683+ianmacartney@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:42:03 -0700 Subject: [PATCH 04/10] test oversized values --- example/convex/oversized.test.ts | 110 ++++++++++++++++++++++++++++ example/convex/oversized.ts | 119 +++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 example/convex/oversized.test.ts create mode 100644 example/convex/oversized.ts diff --git a/example/convex/oversized.test.ts b/example/convex/oversized.test.ts new file mode 100644 index 00000000..1d310b6f --- /dev/null +++ b/example/convex/oversized.test.ts @@ -0,0 +1,110 @@ +/// + +import { expect, describe, test, vi, beforeEach, afterEach } from "vitest"; +import { initConvexTest } from "./setup.test"; +import { components, internal } from "./_generated/api"; +import { assert } from "convex-helpers"; +import { getStatus } from "@convex-dev/workflow"; +import { workflow } from "./example"; + +describe("oversized values", () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + afterEach(() => { + vi.useRealTimers(); + }); + + test("large step return value fails workflow and calls onComplete", async () => { + const t = initConvexTest(); + const workflowId = await t.mutation(async (ctx) => { + const wfId = await workflow.start( + ctx, + internal.oversized.largeReturnWorkflow, + {}, + { + onComplete: internal.oversized.onComplete, + startAsync: true, + }, + ); + await ctx.db.insert("flows", { + workflowId: wfId, + in: "largeReturn", + out: null, + }); + return wfId; + }); + await t.finishAllScheduledFunctions(vi.runAllTimers); + + const status = await t.run((ctx) => + getStatus(ctx, components.workflow, workflowId), + ); + expect(status.type).toBe("failed"); + assert(status.type === "failed"); + expect(status.error).toContain("Step return value too large"); + expect(status.error).toContain("900002 bytes"); + + const flow = await t.query(async (ctx) => { + return ctx.db + .query("flows") + .withIndex("workflowId", (q) => q.eq("workflowId", workflowId)) + .first(); + }); + expect(flow).not.toBeNull(); + expect(flow!.out).not.toBeNull(); + expect(flow!.out.kind).toBe("failed"); + expect(flow!.out.error).toContain("Step return value too large"); + }); + + test("large event value fails workflow and calls onComplete", async () => { + const t = initConvexTest(); + const workflowId = await t.mutation(async (ctx) => { + const wfId = await workflow.start( + ctx, + internal.oversized.eventWorkflow, + {}, + { + onComplete: internal.oversized.onComplete, + startAsync: true, + }, + ); + await ctx.db.insert("flows", { + workflowId: wfId, + in: "eventWorkflow", + out: null, + }); + return wfId; + }); + // Let the workflow start and reach the awaitEvent point + await t.finishAllScheduledFunctions(vi.runAllTimers); + + const status = await t.run((ctx) => + getStatus(ctx, components.workflow, workflowId), + ); + expect(status.type).toBe("inProgress"); + + // Send the oversized event + await t.mutation(internal.oversized.sendBigEvent, { workflowId }); + await t.finishAllScheduledFunctions(vi.runAllTimers); + await t.finishAllScheduledFunctions(vi.runAllTimers); + + const status2 = await t.run((ctx) => + getStatus(ctx, components.workflow, workflowId), + ); + expect(status2.type).toBe("failed"); + assert(status2.type === "failed"); + expect(status2.error).toContain("Step return value too large"); + expect(status2.error).toContain("900002 bytes"); + + const flow = await t.query(async (ctx) => { + return ctx.db + .query("flows") + .withIndex("workflowId", (q) => q.eq("workflowId", workflowId)) + .first(); + }); + expect(flow).not.toBeNull(); + expect(flow!.out).not.toBeNull(); + expect(flow!.out.kind).toBe("failed"); + expect(flow!.out.error).toContain("Step return value too large"); + }); +}); diff --git a/example/convex/oversized.ts b/example/convex/oversized.ts new file mode 100644 index 00000000..25442d25 --- /dev/null +++ b/example/convex/oversized.ts @@ -0,0 +1,119 @@ +import { v } from "convex/values"; +import { + sendEvent, + defineEvent, + type WorkflowId, +} from "@convex-dev/workflow"; +import { components, internal } from "./_generated/api.js"; +import { internalAction, internalMutation } from "./_generated/server.js"; +import { vWorkflowId } from "@convex-dev/workflow"; +import { vResultValidator } from "@convex-dev/workpool"; +import { workflow } from "./example.js"; + +// Action that returns a value larger than 800KB. +export const largeReturnAction = internalAction({ + args: {}, + returns: v.string(), + handler: async (): Promise => { + return "x".repeat(900_000); + }, +}); + +export const largeReturnWorkflow = workflow + .define({ + args: {}, + }) + .handler(async (step) => { + const result = await step.runAction(internal.oversized.largeReturnAction, {}); + return result; + }); + +export const bigEvent = defineEvent({ + name: "bigEvent", + validator: v.string(), +}); + +export const eventWorkflow = workflow + .define({ + args: {}, + }) + .handler(async (step) => { + const result = await step.awaitEvent(bigEvent); + return result; + }); + +export const sendBigEvent = internalMutation({ + args: { + workflowId: vWorkflowId, + }, + returns: v.null(), + handler: async (ctx, args) => { + await sendEvent(ctx, components.workflow, { + ...bigEvent, + workflowId: args.workflowId, + value: "y".repeat(900_000), + }); + }, +}); + +export const onComplete = internalMutation({ + args: { + workflowId: vWorkflowId, + result: vResultValidator, + context: v.optional(v.any()), + }, + returns: v.null(), + handler: async (ctx, args) => { + const flow = await ctx.db + .query("flows") + .withIndex("workflowId", (q) => q.eq("workflowId", args.workflowId)) + .first(); + if (!flow) return null; + await ctx.db.patch(flow._id, { out: args.result }); + return null; + }, +}); + +export const startLargeReturn = internalMutation({ + args: {}, + returns: vWorkflowId, + handler: async (ctx) => { + const workflowId: WorkflowId = await workflow.start( + ctx, + internal.oversized.largeReturnWorkflow, + {}, + { + onComplete: internal.oversized.onComplete, + startAsync: true, + }, + ); + await ctx.db.insert("flows", { + workflowId, + in: "largeReturn", + out: null, + }); + return workflowId; + }, +}); + +export const startEventWorkflow = internalMutation({ + args: {}, + returns: vWorkflowId, + handler: async (ctx) => { + const workflowId: WorkflowId = await workflow.start( + ctx, + internal.oversized.eventWorkflow, + {}, + { + onComplete: internal.oversized.onComplete, + startAsync: true, + }, + ); + await ctx.db.insert("flows", { + workflowId, + in: "eventWorkflow", + out: null, + }); + return workflowId; + }, +}); From 35d3de6497b54ae4a0929258e93b915bf5c40cb0 Mon Sep 17 00:00:00 2001 From: Ian Macartney <366683+ianmacartney@users.noreply.github.com> Date: Thu, 16 Apr 2026 19:40:23 -0700 Subject: [PATCH 05/10] codegen --- example/convex/_generated/api.d.ts | 2 ++ src/component/_generated/api.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/example/convex/_generated/api.d.ts b/example/convex/_generated/api.d.ts index a01f78be..3c3163ae 100644 --- a/example/convex/_generated/api.d.ts +++ b/example/convex/_generated/api.d.ts @@ -14,6 +14,7 @@ import type * as e2e from "../e2e.js"; import type * as example from "../example.js"; import type * as inlineTest from "../inlineTest.js"; import type * as nestedWorkflow from "../nestedWorkflow.js"; +import type * as oversized from "../oversized.js"; import type * as passingSignals from "../passingSignals.js"; import type * as test_oldSyntax from "../test/oldSyntax.js"; import type * as transcription from "../transcription.js"; @@ -32,6 +33,7 @@ declare const fullApi: ApiFromModules<{ example: typeof example; inlineTest: typeof inlineTest; nestedWorkflow: typeof nestedWorkflow; + oversized: typeof oversized; passingSignals: typeof passingSignals; "test/oldSyntax": typeof test_oldSyntax; transcription: typeof transcription; diff --git a/src/component/_generated/api.ts b/src/component/_generated/api.ts index 9a930507..3e00bc83 100644 --- a/src/component/_generated/api.ts +++ b/src/component/_generated/api.ts @@ -12,6 +12,7 @@ import type * as event from "../event.js"; import type * as journal from "../journal.js"; import type * as logging from "../logging.js"; import type * as model from "../model.js"; +import type * as oversizedValues from "../oversizedValues.js"; import type * as pool from "../pool.js"; import type * as utils from "../utils.js"; import type * as workflow from "../workflow.js"; @@ -28,6 +29,7 @@ const fullApi: ApiFromModules<{ journal: typeof journal; logging: typeof logging; model: typeof model; + oversizedValues: typeof oversizedValues; pool: typeof pool; utils: typeof utils; workflow: typeof workflow; From 52b97d5285aa2d0286ee7ae793091e66eebe5ad7 Mon Sep 17 00:00:00 2001 From: Ian Macartney <366683+ianmacartney@users.noreply.github.com> Date: Thu, 16 Apr 2026 20:41:13 -0700 Subject: [PATCH 06/10] use updated status --- src/component/pool.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/component/pool.ts b/src/component/pool.ts index 862452cb..f35c4077 100644 --- a/src/component/pool.ts +++ b/src/component/pool.ts @@ -159,7 +159,7 @@ async function onCompleteHandler( console.event("stepCompleted", { workflowId, workflowName: workflow.name, - status: args.result.kind, + status: journalEntry.step.runResult!.kind, stepName: journalEntry.step.name, stepNumber: journalEntry.stepNumber, durationMs: journalEntry.step.completedAt - journalEntry.step.startedAt, @@ -167,7 +167,7 @@ async function onCompleteHandler( if (workflow.runResult !== undefined) { if (workflow.runResult.kind !== "canceled") { console.error( - `Workflow: ${workflowId} already ${workflow.runResult.kind} when completing ${stepId} with status ${args.result.kind}`, + `Workflow: ${workflowId} already ${workflow.runResult.kind} when completing ${stepId} with status ${journalEntry.step.runResult!.kind}`, ); } return; From 7594a8152b6c10a2d1dd2393ec17c810d7c70f0f Mon Sep 17 00:00:00 2001 From: Ian Macartney <366683+ianmacartney@users.noreply.github.com> Date: Thu, 16 Apr 2026 20:58:59 -0700 Subject: [PATCH 07/10] fix --- example/convex/oversized.test.ts | 2 ++ example/convex/oversized.ts | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/example/convex/oversized.test.ts b/example/convex/oversized.test.ts index 1d310b6f..9c8ed3c1 100644 --- a/example/convex/oversized.test.ts +++ b/example/convex/oversized.test.ts @@ -24,6 +24,7 @@ describe("oversized values", () => { {}, { onComplete: internal.oversized.onComplete, + context: {}, startAsync: true, }, ); @@ -65,6 +66,7 @@ describe("oversized values", () => { {}, { onComplete: internal.oversized.onComplete, + context: {}, startAsync: true, }, ); diff --git a/example/convex/oversized.ts b/example/convex/oversized.ts index 25442d25..21789487 100644 --- a/example/convex/oversized.ts +++ b/example/convex/oversized.ts @@ -60,7 +60,7 @@ export const onComplete = internalMutation({ args: { workflowId: vWorkflowId, result: vResultValidator, - context: v.optional(v.any()), + context: v.any(), }, returns: v.null(), handler: async (ctx, args) => { @@ -84,6 +84,7 @@ export const startLargeReturn = internalMutation({ {}, { onComplete: internal.oversized.onComplete, + context: {}, startAsync: true, }, ); @@ -106,6 +107,7 @@ export const startEventWorkflow = internalMutation({ {}, { onComplete: internal.oversized.onComplete, + context: {}, startAsync: true, }, ); From 34c956a2e94079e5c860b6e4b822d500828ad0d6 Mon Sep 17 00:00:00 2001 From: Ian Macartney <366683+ianmacartney@users.noreply.github.com> Date: Thu, 23 Apr 2026 19:20:32 -0700 Subject: [PATCH 08/10] remove unused start fns --- example/convex/oversized.test.ts | 2 -- example/convex/oversized.ts | 57 +++----------------------------- 2 files changed, 5 insertions(+), 54 deletions(-) diff --git a/example/convex/oversized.test.ts b/example/convex/oversized.test.ts index 9c8ed3c1..f96917f4 100644 --- a/example/convex/oversized.test.ts +++ b/example/convex/oversized.test.ts @@ -43,7 +43,6 @@ describe("oversized values", () => { expect(status.type).toBe("failed"); assert(status.type === "failed"); expect(status.error).toContain("Step return value too large"); - expect(status.error).toContain("900002 bytes"); const flow = await t.query(async (ctx) => { return ctx.db @@ -88,7 +87,6 @@ describe("oversized values", () => { // Send the oversized event await t.mutation(internal.oversized.sendBigEvent, { workflowId }); await t.finishAllScheduledFunctions(vi.runAllTimers); - await t.finishAllScheduledFunctions(vi.runAllTimers); const status2 = await t.run((ctx) => getStatus(ctx, components.workflow, workflowId), diff --git a/example/convex/oversized.ts b/example/convex/oversized.ts index 21789487..03ec9f4c 100644 --- a/example/convex/oversized.ts +++ b/example/convex/oversized.ts @@ -1,9 +1,5 @@ import { v } from "convex/values"; -import { - sendEvent, - defineEvent, - type WorkflowId, -} from "@convex-dev/workflow"; +import { sendEvent, defineEvent } from "@convex-dev/workflow"; import { components, internal } from "./_generated/api.js"; import { internalAction, internalMutation } from "./_generated/server.js"; import { vWorkflowId } from "@convex-dev/workflow"; @@ -24,7 +20,10 @@ export const largeReturnWorkflow = workflow args: {}, }) .handler(async (step) => { - const result = await step.runAction(internal.oversized.largeReturnAction, {}); + const result = await step.runAction( + internal.oversized.largeReturnAction, + {}, + ); return result; }); @@ -73,49 +72,3 @@ export const onComplete = internalMutation({ return null; }, }); - -export const startLargeReturn = internalMutation({ - args: {}, - returns: vWorkflowId, - handler: async (ctx) => { - const workflowId: WorkflowId = await workflow.start( - ctx, - internal.oversized.largeReturnWorkflow, - {}, - { - onComplete: internal.oversized.onComplete, - context: {}, - startAsync: true, - }, - ); - await ctx.db.insert("flows", { - workflowId, - in: "largeReturn", - out: null, - }); - return workflowId; - }, -}); - -export const startEventWorkflow = internalMutation({ - args: {}, - returns: vWorkflowId, - handler: async (ctx) => { - const workflowId: WorkflowId = await workflow.start( - ctx, - internal.oversized.eventWorkflow, - {}, - { - onComplete: internal.oversized.onComplete, - context: {}, - startAsync: true, - }, - ); - await ctx.db.insert("flows", { - workflowId, - in: "eventWorkflow", - out: null, - }); - return workflowId; - }, -}); From 8786df80aadb7ae05575a4b1656e4665ede1d5fd Mon Sep 17 00:00:00 2001 From: Ian Macartney <366683+ianmacartney@users.noreply.github.com> Date: Thu, 23 Apr 2026 19:28:57 -0700 Subject: [PATCH 09/10] use assert --- example/convex/oversized.test.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/example/convex/oversized.test.ts b/example/convex/oversized.test.ts index f96917f4..45444e13 100644 --- a/example/convex/oversized.test.ts +++ b/example/convex/oversized.test.ts @@ -51,9 +51,10 @@ describe("oversized values", () => { .first(); }); expect(flow).not.toBeNull(); - expect(flow!.out).not.toBeNull(); - expect(flow!.out.kind).toBe("failed"); - expect(flow!.out.error).toContain("Step return value too large"); + assert(flow); + expect(flow.out).not.toBeNull(); + expect(flow.out.kind).toBe("failed"); + expect(flow.out.error).toContain("Step return value too large"); }); test("large event value fails workflow and calls onComplete", async () => { From bf2f490b5b57549da652bd5b4ef75db041b2f9c4 Mon Sep 17 00:00:00 2001 From: Ian Macartney <366683+ianmacartney@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:49:14 -0700 Subject: [PATCH 10/10] feedback --- src/component/event.ts | 12 ++---------- src/component/oversizedValues.ts | 10 +--------- src/component/pool.ts | 11 ++++------- 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/component/event.ts b/src/component/event.ts index 779b2d56..f0fef08f 100644 --- a/src/component/event.ts +++ b/src/component/event.ts @@ -41,11 +41,7 @@ export async function awaitEvent( stepId: entry._id, }, }); - entry.step.runResult = await checkForOversizedResult( - ctx, - event.state.result, - { stepId: entry._id }, - ); + entry.step.runResult = checkForOversizedResult(event.state.result); entry.step.inProgress = false; entry.step.completedAt = Date.now(); break; @@ -151,11 +147,7 @@ export const send = mutation({ ); assert(step.step.kind === "event", "Step is not an event"); step.step.eventId = event._id; - step.step.runResult = await checkForOversizedResult( - ctx, - args.result, - { stepId: step._id }, - ); + step.step.runResult = checkForOversizedResult(args.result); step.step.inProgress = false; step.step.completedAt = Date.now(); await ctx.db.replace(step._id, step); diff --git a/src/component/oversizedValues.ts b/src/component/oversizedValues.ts index 9502485c..ee6905ab 100644 --- a/src/component/oversizedValues.ts +++ b/src/component/oversizedValues.ts @@ -1,7 +1,5 @@ import { type Value, convexToJson, getConvexSize } from "convex/values"; import type { RunResult } from "@convex-dev/workpool"; -import type { MutationCtx } from "./_generated/server.js"; -import type { Id } from "./_generated/dataModel.js"; export const MAX_RETURN_VALUE_SIZE = 800 << 10; // 800 KiB const PREVIEW_SIZE = 128 << 10; // 128 KB @@ -24,13 +22,7 @@ export function checkReturnValueSize( return null; } -export async function checkForOversizedResult( - _ctx: MutationCtx, - result: RunResult, - _opts: { - stepId: Id<"steps">; - }, -): Promise { +export function checkForOversizedResult(result: RunResult): RunResult { if (result.kind !== "success") { return result; } diff --git a/src/component/pool.ts b/src/component/pool.ts index f35c4077..87d5a921 100644 --- a/src/component/pool.ts +++ b/src/component/pool.ts @@ -148,18 +148,15 @@ async function onCompleteHandler( } journalEntry.step.inProgress = false; journalEntry.step.completedAt = Date.now(); - journalEntry.step.runResult = await checkForOversizedResult( - ctx, - args.result, - { stepId }, - ); + const runResult = checkForOversizedResult(args.result); + journalEntry.step.runResult = runResult; await ctx.db.replace(journalEntry._id, journalEntry); console.debug(`Completed execution of ${stepId}`, journalEntry); console.event("stepCompleted", { workflowId, workflowName: workflow.name, - status: journalEntry.step.runResult!.kind, + status: journalEntry.step.runResult.kind, stepName: journalEntry.step.name, stepNumber: journalEntry.stepNumber, durationMs: journalEntry.step.completedAt - journalEntry.step.startedAt, @@ -167,7 +164,7 @@ async function onCompleteHandler( if (workflow.runResult !== undefined) { if (workflow.runResult.kind !== "canceled") { console.error( - `Workflow: ${workflowId} already ${workflow.runResult.kind} when completing ${stepId} with status ${journalEntry.step.runResult!.kind}`, + `Workflow: ${workflowId} already ${workflow.runResult.kind} when completing ${stepId} with status ${journalEntry.step.runResult.kind}`, ); } return;