Skip to content

Commit

Permalink
Updates the trigger, batchTrigger and their *AndWait variants t…
Browse files Browse the repository at this point in the history
…o use the first parameter for the payload/items, and the second parameter for options (#1045)

Also always returns a `TaskRunResult` object from `triggerAndWait` instead of rethrowing subtask errors in the parent
  • Loading branch information
ericallam committed Apr 19, 2024
1 parent b82db67 commit 374edef
Show file tree
Hide file tree
Showing 18 changed files with 373 additions and 322 deletions.
56 changes: 56 additions & 0 deletions .changeset/shaggy-spoons-taste.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
"@trigger.dev/sdk": patch
"@trigger.dev/core": patch
---

Updates the `trigger`, `batchTrigger` and their `*AndWait` variants to use the first parameter for the payload/items, and the second parameter for options.

Before:

```ts
await yourTask.trigger({ payload: { foo: "bar" }, options: { idempotencyKey: "key_1234" } });
await yourTask.triggerAndWait({ payload: { foo: "bar" }, options: { idempotencyKey: "key_1234" } });

await yourTask.batchTrigger({ items: [{ payload: { foo: "bar" } }, { payload: { foo: "baz" } }] });
await yourTask.batchTriggerAndWait({ items: [{ payload: { foo: "bar" } }, { payload: { foo: "baz" } }] });
```

After:

```ts
await yourTask.trigger({ foo: "bar" }, { idempotencyKey: "key_1234" });
await yourTask.triggerAndWait({ foo: "bar" }, { idempotencyKey: "key_1234" });

await yourTask.batchTrigger([{ payload: { foo: "bar" } }, { payload: { foo: "baz" } }]);
await yourTask.batchTriggerAndWait([{ payload: { foo: "bar" } }, { payload: { foo: "baz" } }]);
```

We've also changed the API of the `triggerAndWait` result. Before, if the subtask that was triggered finished with an error, we would automatically "rethrow" the error in the parent task.

Now instead we're returning a `TaskRunResult` object that allows you to discriminate between successful and failed runs in the subtask:

Before:

```ts
try {
const result = await yourTask.triggerAndWait({ foo: "bar" });

// result is the output of your task
console.log("result", result);

} catch (error) {
// handle subtask errors here
}
```

After:

```ts
const result = await yourTask.triggerAndWait({ foo: "bar" });

if (result.ok) {
console.log(`Run ${result.id} succeeded with output`, result.output);
} else {
console.log(`Run ${result.id} failed with error`, result.error);
}
```
2 changes: 1 addition & 1 deletion docs/v3/errors-retrying.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const myTask = task({
maxAttempts: 10,
},
run: async (payload: string) => {
const result = await otherTask.triggerAndWait({ payload: "some data" });
const result = await otherTask.triggerAndWait("some data");
//...do other stuff
},
});
Expand Down
6 changes: 3 additions & 3 deletions docs/v3/migration-defer.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,15 @@ export async function runLongRunningTask() {
}
```

In Trigger.dev your logic goes in the `run` function of a task. You can then `trigger` and `batchTrigger` that task, with a payload and options.
In Trigger.dev your logic goes in the `run` function of a task. You can then `trigger` and `batchTrigger` that task, with a payload as the first argument.

```ts /app/actions/actions.ts
"use server";

import { longRunningTask } from "@/trigger/someTasks";

export async function runLongRunningTask() {
return await longRunningTask.trigger({ payload: { foo: "bar" } });
return await longRunningTask.trigger({ foo: "bar" });
}
```

Expand Down Expand Up @@ -243,7 +243,7 @@ export const longRunningTask = task({
import { longRunningTask } from "@/trigger/longRunningTask";

export async function runLongRunningTask() {
return await longRunningTask.trigger({ payload: { foo: "bar" } });
return await longRunningTask.trigger({ foo: "bar" });
}
```

Expand Down
49 changes: 19 additions & 30 deletions docs/v3/queue-concurrency.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -107,24 +107,19 @@ export async function POST(request: Request) {

if (data.branch === "main") {
//trigger the task, with a different queue
const handle = await generatePullRequest.trigger({
payload: data,
options: {
queue: {
//the "main-branch" queue will have a concurrency limit of 10
//this triggered run will use that queue
name: "main-branch",
concurrencyLimit: 10,
},
const handle = await generatePullRequest.trigger(data, {
queue: {
//the "main-branch" queue will have a concurrency limit of 10
//this triggered run will use that queue
name: "main-branch",
concurrencyLimit: 10,
},
});

return Response.json(handle);
} else {
//triggered with the default (concurrency of 1)
const handle = await generatePullRequest.trigger({
payload: data,
});
const handle = await generatePullRequest.trigger(data);
return Response.json(handle);
}
}
Expand All @@ -146,32 +141,26 @@ export async function POST(request: Request) {

if (data.isFreeUser) {
//free users can only have 1 PR generated at a time
const handle = await generatePullRequest.trigger({
payload: data,
options: {
queue: {
//every free user gets a queue with a concurrency limit of 1
name: "free-users",
concurrencyLimit: 1,
},
concurrencyKey: data.userId,
const handle = await generatePullRequest.trigger(data, {
queue: {
//every free user gets a queue with a concurrency limit of 1
name: "free-users",
concurrencyLimit: 1,
},
concurrencyKey: data.userId,
});

//return a success response with the handle
return Response.json(handle);
} else {
//trigger the task, with a different queue
const handle = await generatePullRequest.trigger({
payload: data,
options: {
queue: {
//every paid user gets a queue with a concurrency limit of 10
name: "paid-users",
concurrencyLimit: 10,
},
concurrencyKey: data.userId,
const handle = await generatePullRequest.trigger(data, {
queue: {
//every paid user gets a queue with a concurrency limit of 10
name: "paid-users",
concurrencyLimit: 10,
},
concurrencyKey: data.userId,
});

//return a success response with the handle
Expand Down
2 changes: 1 addition & 1 deletion docs/v3/tasks-overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { helloWorldTask } from "./trigger/hello-world";

async function triggerHelloWorld() {
//This triggers the task and return a handle
const handle = await helloWorld.trigger({ payload: { message: "Hello world!" } });
const handle = await helloWorld.trigger({ message: "Hello world!" });

//You can use the handle to check the status of the task, cancel and retry it.
console.log("Task is running with handle", handle.id);
Expand Down
65 changes: 36 additions & 29 deletions docs/v3/triggering.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export async function POST(request: Request) {
const data = await request.json();

//trigger your task
const handle = await emailSequence.trigger({ payload: { to: data.email, name: data.name } });
const handle = await emailSequence.trigger({ to: data.email, name: data.name });

//return a success response with the handle
return Response.json(handle);
Expand All @@ -67,7 +67,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
const data = await request.json();

//trigger your task
const handle = await emailSequence.trigger({ payload: { to: data.email, name: data.name } });
const handle = await emailSequence.trigger({ to: data.email, name: data.name });

//return a success response with the handle
return json(handle);
Expand All @@ -91,9 +91,9 @@ export async function POST(request: Request) {
const data = await request.json();

//batch trigger your task
const batchHandle = await emailSequence.batchTrigger({
items: data.users.map((u) => ({ payload: { to: u.email, name: u.name } })),
});
const batchHandle = await emailSequence.batchTrigger(
data.users.map((u) => ({ payload: { to: u.email, name: u.name } }))
);

//return a success response with the handle
return Response.json(batchHandle);
Expand All @@ -112,9 +112,9 @@ export async function action({ request, params }: ActionFunctionArgs) {
const data = await request.json();

//batch trigger your task
const batchHandle = await emailSequence.batchTrigger({
items: data.users.map((u) => ({ payload: { to: u.email, name: u.name } })),
});
const batchHandle = await emailSequence.batchTrigger(
data.users.map((u) => ({ payload: { to: u.email, name: u.name } }))
);

//return a success response with the handle
return json(batchHandle);
Expand All @@ -137,7 +137,7 @@ import { myOtherTask } from "~/trigger/my-other-task";
export const myTask = task({
id: "my-task",
run: async (payload: string) => {
const handle = await myOtherTask.trigger({ payload: "some data" });
const handle = await myOtherTask.trigger("some data");

//...do other stuff
},
Expand All @@ -154,7 +154,7 @@ import { myOtherTask } from "~/trigger/my-other-task";
export const myTask = task({
id: "my-task",
run: async (payload: string) => {
const batchHandle = await myOtherTask.batchTrigger({ items: [{ payload: "some data" }] });
const batchHandle = await myOtherTask.batchTrigger([{ payload: "some data" }]);

//...do other stuff
},
Expand All @@ -168,16 +168,18 @@ This is where it gets interesting. You can trigger a task and then wait for the
<Accordion title="Don't use this in parallel, e.g. with `Promise.all()`">
Instead, use `batchTriggerAndWait()` if you can, or a for loop if you can't.

To control concurrency using batch triggers, you can set `queue.concurrencyLimit` on the child task.
To control concurrency using batch triggers, you can set `queue.concurrencyLimit` on the child task.

<CodeGroup>

```ts /trigger/batch.ts
export const batchTask = task({
id: "batch-task",
run: async (payload: string) => {
const results = await childTask.batchTriggerAndWait({
items: [{ payload: "item1" }, { payload: "item2" }],
});
const results = await childTask.batchTriggerAndWait([
{ payload: "item1" },
{ payload: "item2" },
]);
console.log("Results", results);

//...do stuff with the results
Expand All @@ -192,14 +194,15 @@ export const loopTask = task({
//this will be slower than the batch version
//as we have to resume the parent after each iteration
for (let i = 0; i < 2; i++) {
const result = await childTask.triggerAndWait({ payload: `item${i}` });
const result = await childTask.triggerAndWait(`item${i}`);
console.log("Result", result);

//...do stuff with the result
}
},
});
```

</CodeGroup>

</Accordion>
Expand All @@ -208,7 +211,7 @@ export const loopTask = task({
export const parentTask = task({
id: "parent-task",
run: async (payload: string) => {
const result = await batchChildTask.triggerAndWait({ payload: "some-data" });
const result = await batchChildTask.triggerAndWait("some-data");
console.log("Result", result);

//...do stuff with the result
Expand All @@ -223,16 +226,18 @@ You can batch trigger a task and wait for all the results. This is useful for th
<Accordion title="Don't use this in parallel, e.g. with `Promise.all()`">
Instead, pass in all items at once and set an appropriate `maxConcurrency`. Alternatively, use sequentially with a for loop.

To control concurrency, you can set `queue.concurrencyLimit` on the child task.
To control concurrency, you can set `queue.concurrencyLimit` on the child task.

<CodeGroup>

```ts /trigger/batch.ts
export const batchTask = task({
id: "batch-task",
run: async (payload: string) => {
const results = await childTask.batchTriggerAndWait({
items: [{ payload: "item1" }, { payload: "item2" }],
});
const results = await childTask.batchTriggerAndWait([
{ payload: "item1" },
{ payload: "item2" },
]);
console.log("Results", results);

//...do stuff with the results
Expand All @@ -247,16 +252,18 @@ export const loopTask = task({
//this will be slower than a single batchTriggerAndWait()
//as we have to resume the parent after each iteration
for (let i = 0; i < 2; i++) {
const result = await childTask.batchTriggerAndWait({
items: [{ payload: `itemA${i}` }, { payload: `itemB${i}` }],
});
const result = await childTask.batchTriggerAndWait([
{ payload: `itemA${i}` },
{ payload: `itemB${i}` },
]);
console.log("Result", result);

//...do stuff with the result
}
},
});
```

</CodeGroup>

</Accordion>
Expand All @@ -265,9 +272,11 @@ export const loopTask = task({
export const batchParentTask = task({
id: "parent-task",
run: async (payload: string) => {
const results = await childTask.batchTriggerAndWait({
items: [{ payload: "item4" }, { payload: "item5" }, { payload: "item6" }],
});
const results = await childTask.batchTriggerAndWait([
{ payload: "item4" },
{ payload: "item5" },
{ payload: "item6" },
]);
console.log("Results", results);

//...do stuff with the result
Expand Down Expand Up @@ -326,9 +335,7 @@ import { createAvatar } from "@/trigger/create-avatar";
export async function create() {
try {
const handle = await createAvatar.trigger({
payload: {
userImage: "http://...",
},
userImage: "http://...",
});

return { handle };
Expand Down
4 changes: 1 addition & 3 deletions docs/v3/upgrading-from-v2.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ We've unified triggering in v3. You use `trigger()` or `batchTrigger()` which yo
async function yourBackendFunction() {
//call `trigger()` on any task
const handle = await openaiTask.trigger({
payload: {
prompt: "Tell me a programming joke",
},
prompt: "Tell me a programming joke",
});
}
```
Expand Down

0 comments on commit 374edef

Please sign in to comment.