Today we're announcing a slew of improvements to our batch trigger feature: New limits, a dedicated dashboard page, new SDK methods, and more
Increased batch size
We've heard from quite a few people that our batch size limit of 100 items is too low, so we've built a new batch endpoint that can handle substantially more items, and we've increased the limit to 500 items.
We achieved this by changing the way the endpoint works to process items asynchronously. This means that the endpoint will return a response immediately after receiving the batch, and the items will be processed in the background. Previously the endpoint would wait for all items to be processed before returning a response, which would sometimes cause timeouts or just very slow responses.
NOTE
To take advantage of the new batch size limit, you'll need to be on version 3.3.0 or later of the SDK.
New batches page in the dashboard
See all your batches together in a dedicated dashboard page and view all runs filtered by batch. Here's a short run-through:
New batch trigger SDK methods
We have added some additional methods to the SDK to make working with batches even easier:
batch.trigger
batch.trigger allows you to trigger multiple tasks in a single batch. You can pass an array of objects, each with an id for the task you want to trigger and a payload object with the data you want to pass to the task.
src/app/routes/batch.ts
import { batch } from "@trigger.dev/sdk/v3";
// 👆 this is new
import type { myTask1, myTask2 } from "~/trigger/myTasks";
export async function POST(request: Request) {
//get the JSON from the request
const data = await request.json();
// Pass a union of the tasks to `trigger()` as a generic argument, giving you full type checking
const result = await batch.trigger<typeof myTask1 | typeof myTask2>([
// Because we're using a union, we can pass in multiple tasks by ID
batch.triggerAndWait is similar to batch.trigger, but it will wait for all tasks to complete before returning a response (and can only be used inside another task)
src/trigger/tasks.ts
import { batch, task } from "@trigger.dev/sdk/v3";
export const parentTask = task({
id: "parent-task",
run: async (payload: string) => {
// 👇 Pass a union of all the tasks you want to trigger
const results = await batch.triggerAndWait<
typeof childTask1 | typeof childTask2
>([
{ id: "child-task-1", payload: { foo: "World" } }, // 👈 The payload is typed correctly based on the task `id`
{ id: "child-task-2", payload: { bar: 42 } }, // 👈 The payload is typed correctly based on the task `id`
]);
for (const result of results) {
if (result.ok) {
// 👇 Narrow the type of the result based on the taskIdentifier
switch (result.taskIdentifier) {
case "child-task-1":
console.log("Child task 1 output", result.output); // 👈 result.output is typed as a string
break;
case "child-task-2":
console.log("Child task 2 output", result.output); // 👈 result.output is typed as a number
break;
}
} else {
console.error("Error", result.error); // 👈 result.error is the error that caused the run to fail
}
}
},
});
export const childTask1 = task({
id: "child-task-1",
run: async (payload: { foo: string }) => {
return `Hello ${payload}`;
},
});
export const childTask2 = task({
id: "child-task-2",
run: async (payload: { bar: number }) => {
return bar + 1;
},
});
batch.triggerByTask
You can batch trigger multiple different tasks by passing in the task instances. This function is especially useful when you have a static set of tasks you want to trigger:
src/trigger/tasks.ts
import { batch, task, runs } from "@trigger.dev/sdk/v3";
export const parentTask = task({
id: "parent-task",
run: async (payload: string) => {
const results = await batch.triggerByTask([
{ task: childTask1, payload: { foo: "World" } }, // 👈 The payload is typed correctly based on the task instance
{ task: childTask2, payload: { bar: 42 } }, // 👈 The payload is typed correctly based on the task instance
]);
// 👇 results.runs is a tuple, allowing you to get type safety without needing to narrow
const run1 = await runs.retrieve(results.runs[0]); // 👈 run1 is typed as the output of childTask1
const run2 = await runs.retrieve(results.runs[1]); // 👈 run2 is typed as the output of childTask2
},
});
export const childTask1 = task({
id: "child-task-1",
run: async (payload: { foo: string }) => {
return `Hello ${payload}`;
},
});
export const childTask2 = task({
id: "child-task-2",
run: async (payload: { bar: number }) => {
return bar + 1;
},
});
batch.triggerByTaskAndWait
batch.triggerByTaskAndWait is similar to batch.triggerByTask, but it will wait for all tasks to complete before returning a response (and can only be used inside another task)
src/trigger/tasks.ts
import { batch, task, runs } from "@trigger.dev/sdk/v3";
You can now retrieve a batch by ID using the batch.retrieve method:
import { batch } from "@trigger.dev/sdk/v3";
// Retrieve a batch by ID
const batch = await batch.retrieve("batch_1234");
Batch Idempotency
We've added support for idempotency keys to the batch trigger endpoint. This means that you can pass an idempotencyKey and we'll ensure that the batch is only processed once, even if the request is retried.
src/app/routes/batch.ts
import { batch } from "@trigger.dev/sdk/v3";
export async function POST(request: Request) {
//get the JSON from the request
const data = await request.json();
// Pass an idempotency key to `trigger()` to ensure the batch is only processed once
const result = await batch.trigger<typeof myTask1 | typeof myTask2>(