+103
-2
@@ -170,6 +170,107 @@ tasks.onComplete(({ ctx, result }) => {
|
||||
});
|
||||
```
|
||||
|
||||
### onCancel
|
||||
|
||||
<Note>Available in v4.0.0-beta.12 and later.</Note>
|
||||
|
||||
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.
|
||||
|
||||
```ts
|
||||
tasks.onCancel(({ ctx, signal }) => {
|
||||
console.log("Run cancelled", signal);
|
||||
});
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```ts
|
||||
import { logger, tasks, schemaTask } from "@trigger.dev/sdk";
|
||||
import { streamText } from "ai";
|
||||
import { z } from "zod";
|
||||
|
||||
export const interruptibleChat = schemaTask({
|
||||
id: "interruptible-chat",
|
||||
description: "Chat with the AI",
|
||||
schema: z.object({
|
||||
prompt: z.string().describe("The prompt to chat with the AI"),
|
||||
}),
|
||||
run: async ({ prompt }, { signal }) => {
|
||||
const chunks: TextStreamPart<{}>[] = [];
|
||||
|
||||
// 👇 This is a global onCancel hook, but it's inside of the run function
|
||||
tasks.onCancel(async () => {
|
||||
// We have access to the chunks here, and can save them to the database
|
||||
await saveChunksToDatabase(chunks);
|
||||
});
|
||||
|
||||
try {
|
||||
const result = streamText({
|
||||
model: getModel(),
|
||||
prompt,
|
||||
experimental_telemetry: {
|
||||
isEnabled: true,
|
||||
},
|
||||
tools: {},
|
||||
abortSignal: signal, // 👈 Pass the signal to the streamText function, which aborts with the run is cancelled
|
||||
onChunk: ({ chunk }) => {
|
||||
chunks.push(chunk);
|
||||
},
|
||||
});
|
||||
|
||||
const textParts = [];
|
||||
|
||||
for await (const part of result.textStream) {
|
||||
textParts.push(part);
|
||||
}
|
||||
|
||||
return textParts.join("");
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.name === "AbortError") {
|
||||
// streamText will throw an AbortError if the signal is aborted, so we can handle it here
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
The `onCancel` hook can optionally wait for the `run` function to finish, and access the output of the run:
|
||||
|
||||
```ts
|
||||
import { logger, task } from "@trigger.dev/sdk";
|
||||
import { setTimeout } from "node:timers/promises";
|
||||
|
||||
export const cancelExampleTask = task({
|
||||
id: "cancel-example",
|
||||
// Signal will be aborted when the task is cancelled 👇
|
||||
run: async (payload: { message: string }, { signal }) => {
|
||||
try {
|
||||
// We pass the signal to setTimeout to abort the timeout if the task is cancelled
|
||||
await setTimeout(10_000, undefined, { signal });
|
||||
} catch (error) {
|
||||
// Ignore the abort error
|
||||
}
|
||||
|
||||
// Do some more work here
|
||||
|
||||
return {
|
||||
message: "Hello, world!",
|
||||
};
|
||||
},
|
||||
onCancel: async ({ runPromise }) => {
|
||||
// You can await the runPromise to get the output of the task
|
||||
const output = await runPromise;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
You will have up to 30 seconds to complete the `runPromise` in the `onCancel` hook. After that
|
||||
point the process will be killed.
|
||||
</Note>
|
||||
|
||||
### Improved middleware and locals
|
||||
|
||||
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({
|
||||
id: "my-task",
|
||||
onStart: ({ payload, ctx }) => {},
|
||||
// The run function still uses separate parameters
|
||||
run: async ( payload, { ctx }) => {},
|
||||
run: async (payload, { ctx }) => {},
|
||||
});
|
||||
```
|
||||
|
||||
@@ -760,4 +861,4 @@ const batchHandle = await tasks.batchTrigger([
|
||||
// Now you need to call runs.list()
|
||||
const runs = await batchHandle.runs.list();
|
||||
console.log(runs);
|
||||
```
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user