Skip to content

Commit 43a4139

Browse files
authored
docs: onCancel (#2024)
* docs: onCancel * Add availability note
1 parent 7b50984 commit 43a4139

File tree

1 file changed

+103
-2
lines changed

1 file changed

+103
-2
lines changed

docs/upgrade-to-v4.mdx

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,107 @@ tasks.onComplete(({ ctx, result }) => {
170170
});
171171
```
172172

173+
### onCancel
174+
175+
<Note>Available in v4.0.0-beta.12 and later.</Note>
176+
177+
You can now define an `onCancel` hook that is called when a run is cancelled. This is useful if you want to clean up any resources that were allocated for the run.
178+
179+
```ts
180+
tasks.onCancel(({ ctx, signal }) => {
181+
console.log("Run cancelled", signal);
182+
});
183+
```
184+
185+
You can use the `onCancel` hook along with the `signal` passed into the run function to interrupt a call to an external service, for example using the [streamText](https://ai-sdk.dev/docs/reference/ai-sdk-core/stream-text) function from the AI SDK:
186+
187+
```ts
188+
import { logger, tasks, schemaTask } from "@trigger.dev/sdk";
189+
import { streamText } from "ai";
190+
import { z } from "zod";
191+
192+
export const interruptibleChat = schemaTask({
193+
id: "interruptible-chat",
194+
description: "Chat with the AI",
195+
schema: z.object({
196+
prompt: z.string().describe("The prompt to chat with the AI"),
197+
}),
198+
run: async ({ prompt }, { signal }) => {
199+
const chunks: TextStreamPart<{}>[] = [];
200+
201+
// 👇 This is a global onCancel hook, but it's inside of the run function
202+
tasks.onCancel(async () => {
203+
// We have access to the chunks here, and can save them to the database
204+
await saveChunksToDatabase(chunks);
205+
});
206+
207+
try {
208+
const result = streamText({
209+
model: getModel(),
210+
prompt,
211+
experimental_telemetry: {
212+
isEnabled: true,
213+
},
214+
tools: {},
215+
abortSignal: signal, // 👈 Pass the signal to the streamText function, which aborts with the run is cancelled
216+
onChunk: ({ chunk }) => {
217+
chunks.push(chunk);
218+
},
219+
});
220+
221+
const textParts = [];
222+
223+
for await (const part of result.textStream) {
224+
textParts.push(part);
225+
}
226+
227+
return textParts.join("");
228+
} catch (error) {
229+
if (error instanceof Error && error.name === "AbortError") {
230+
// streamText will throw an AbortError if the signal is aborted, so we can handle it here
231+
} else {
232+
throw error;
233+
}
234+
}
235+
},
236+
});
237+
```
238+
239+
The `onCancel` hook can optionally wait for the `run` function to finish, and access the output of the run:
240+
241+
```ts
242+
import { logger, task } from "@trigger.dev/sdk";
243+
import { setTimeout } from "node:timers/promises";
244+
245+
export const cancelExampleTask = task({
246+
id: "cancel-example",
247+
// Signal will be aborted when the task is cancelled 👇
248+
run: async (payload: { message: string }, { signal }) => {
249+
try {
250+
// We pass the signal to setTimeout to abort the timeout if the task is cancelled
251+
await setTimeout(10_000, undefined, { signal });
252+
} catch (error) {
253+
// Ignore the abort error
254+
}
255+
256+
// Do some more work here
257+
258+
return {
259+
message: "Hello, world!",
260+
};
261+
},
262+
onCancel: async ({ runPromise }) => {
263+
// You can await the runPromise to get the output of the task
264+
const output = await runPromise;
265+
},
266+
});
267+
```
268+
269+
<Note>
270+
You will have up to 30 seconds to complete the `runPromise` in the `onCancel` hook. After that
271+
point the process will be killed.
272+
</Note>
273+
173274
### Improved middleware and locals
174275

175276
Our task middleware system is now much more useful. Previously it only ran "around" the `run` function, but now we've hoisted it to the top level and it now runs before/after all the other hooks.
@@ -704,7 +805,7 @@ export const myTask = task({
704805
id: "my-task",
705806
onStart: ({ payload, ctx }) => {},
706807
// The run function still uses separate parameters
707-
run: async ( payload, { ctx }) => {},
808+
run: async (payload, { ctx }) => {},
708809
});
709810
```
710811

@@ -760,4 +861,4 @@ const batchHandle = await tasks.batchTrigger([
760861
// Now you need to call runs.list()
761862
const runs = await batchHandle.runs.list();
762863
console.log(runs);
763-
```
864+
```

0 commit comments

Comments
 (0)