Skip to content

Commit 7c67c23

Browse files
feat: add onError support to serve (#79)
* feat: add onError support to serve * fix: use console.error as default onError and use onError in try/catch --------- Co-authored-by: CahidArda <[email protected]>
1 parent 8f0e385 commit 7c67c23

File tree

5 files changed

+35
-3
lines changed

5 files changed

+35
-3
lines changed

src/error.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ export const formatWorkflowError = (error: unknown): FailureFunctionPayload => {
5656
}
5757
: {
5858
error: "Error",
59-
message: "An error occured while executing workflow.",
59+
message:
60+
"An error occured while executing workflow: " +
61+
`'${typeof error === "string" ? error : JSON.stringify(error)}'`,
6062
};
6163
};

src/serve/index.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export const serveBase = <
6262
useJSONContent,
6363
disableTelemetry,
6464
flowControl,
65+
onError,
6566
} = processOptions<TResponse, TInitialPayload>(options);
6667
telemetry = disableTelemetry ? undefined : telemetry;
6768
const debug = WorkflowLogger.getLogger(verbose);
@@ -234,8 +235,21 @@ export const serveBase = <
234235
try {
235236
return await handler(request);
236237
} catch (error) {
237-
console.error(error);
238-
return new Response(JSON.stringify(formatWorkflowError(error)), {
238+
const formattedError = formatWorkflowError(error);
239+
try {
240+
onError?.(error as Error);
241+
} catch (onErrorError) {
242+
const formattedOnErrorError = formatWorkflowError(onErrorError);
243+
const errorMessage =
244+
`Error while running onError callback: '${formattedOnErrorError.message}'.` +
245+
`\nOriginal error: '${formattedError.message}'`;
246+
247+
console.error(errorMessage);
248+
return new Response(errorMessage, {
249+
status: 500,
250+
}) as TResponse;
251+
}
252+
return new Response(JSON.stringify(formattedError), {
239253
status: 500,
240254
}) as TResponse;
241255
}

src/serve/options.ts

+1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export const processOptions = <TResponse extends Response = Response, TInitialPa
9191
retries: DEFAULT_RETRIES,
9292
useJSONContent: false,
9393
disableTelemetry: false,
94+
onError: console.error,
9495
...options,
9596
};
9697
};

src/serve/serve.test.ts

+7
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ describe("serve", () => {
253253
});
254254

255255
test("should return 500 on error during step execution", async () => {
256+
let onErrorCalled = false;
256257
const { handler: endpoint } = serve(
257258
async (context) => {
258259
await context.run("wrong step", async () => {
@@ -262,6 +263,11 @@ describe("serve", () => {
262263
{
263264
qstashClient,
264265
receiver: undefined,
266+
onError(error) {
267+
expect(error).toBeInstanceOf(Error);
268+
expect(error.message).toBe("some-error");
269+
onErrorCalled = true;
270+
},
265271
}
266272
);
267273

@@ -284,6 +290,7 @@ describe("serve", () => {
284290
receivesRequest: false,
285291
});
286292
expect(called).toBeTrue();
293+
expect(onErrorCalled).toBeTrue();
287294
});
288295

289296
test("should call onFinish with auth-fail if authentication fails", async () => {

src/types.ts

+8
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,14 @@ export type WorkflowServeOptions<
174174
* Url to call if QStash retries are exhausted while executing the workflow
175175
*/
176176
failureUrl?: string;
177+
178+
/**
179+
* Error handler called when an error occurs in the workflow. This is
180+
* different from `failureFunction` in that it is called when an error
181+
* occurs in the workflow, while `failureFunction` is called when QStash
182+
* retries are exhausted.
183+
*/
184+
onError?: (error: Error) => void;
177185
/**
178186
* Failure function called when QStash retries are exhausted while executing
179187
* the workflow. Will overwrite `failureUrl` parameter with the workflow

0 commit comments

Comments
 (0)