From 642f15a06d7beb9bbc45779c779ff7e3907c39b6 Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Wed, 27 Nov 2024 22:38:30 +0000 Subject: [PATCH 1/2] WIP batch docs --- docs/limits.mdx | 87 +++++---- docs/triggering.mdx | 443 +++++++++++++++++++++++++++++++++----------- 2 files changed, 384 insertions(+), 146 deletions(-) diff --git a/docs/limits.mdx b/docs/limits.mdx index 4f07428a98..79053aadd5 100644 --- a/docs/limits.mdx +++ b/docs/limits.mdx @@ -3,15 +3,15 @@ title: "Limits" description: "There are some hard and soft limits that you might hit." --- -import RateLimitHitUseBatchTrigger from '/snippets/rate-limit-hit-use-batchtrigger.mdx'; +import RateLimitHitUseBatchTrigger from "/snippets/rate-limit-hit-use-batchtrigger.mdx"; ## Concurrency limits -| Pricing tier | Limit | -|:---------------- |:-------------------- | -| Free | 5 concurrent runs | -| Hobby | 25 concurrent runs | -| Pro | 100+ concurrent runs | +| Pricing tier | Limit | +| :----------- | :------------------- | +| Free | 5 concurrent runs | +| Hobby | 25 concurrent runs | +| Pro | 100+ concurrent runs | If you need more than 100 concurrent runs on the Pro tier, you can request more by contacting us via [email](https://trigger.dev/contact) or [Discord](https://trigger.dev/discord). @@ -20,28 +20,28 @@ If you need more than 100 concurrent runs on the Pro tier, you can request more Generally speaking each SDK call is an API call. | Limit | Details | -|:----- |:------------------------- | +| :---- | :------------------------ | | API | 1,500 requests per minute | - + ## Queued tasks The number of queued tasks by environment. | Limit | Details | -|:------- |:------------------ | +| :------ | :----------------- | | Dev | At most 500 | | Staging | At most 10 million | | Prod | At most 10 million | ## Schedules -| Pricing tier | Limit | -|:---------------- |:-------------------- | -| Free | 5 per project | -| Hobby | 100 per project | -| Pro | 1,000+ per project | +| Pricing tier | Limit | +| :----------- | :----------------- | +| Free | 5 per project | +| Hobby | 100 per project | +| Pro | 1,000+ per project | When attaching schedules to tasks we strongly recommend you add them [in our dashboard](/tasks/scheduled#attaching-schedules-in-the-dashboard) if they're "static". That way you can control them easily per environment. @@ -49,15 +49,29 @@ If you add them [dynamically using code](/management/schedules/create) make sure If you're creating schedules for your user you will definitely need to request more schedules from us. +## Task payloads and outputs + +| Limit | Details | +| :--------------------- | :-------------------------------------------- | +| Single trigger payload | Must not exceed 3MB | +| Batch trigger payload | The total of all payloads must not exceed 1MB | +| Task outputs | Must not exceed 10MB | + +Payloads and outputs that exceed 512KB will be offloaded to object storage and a presigned URL will be provided to download the data when calling `runs.retrieve`. You don't need to do anything to handle this in your tasks however, as we will transparently upload/download these during operation. + +## Batch size + +A single batch can have a maximum of 500 items. + ## Log retention -| Pricing tier | Limit | -|:---------------- |:--------- | -| Free | 1 day | -| Hobby | 7 days | -| Pro | 30 days | +| Pricing tier | Limit | +| :----------- | :------ | +| Free | 1 day | +| Hobby | 7 days | +| Pro | 30 days | ## Log size @@ -66,25 +80,30 @@ We limit the size of logs to prevent oversized data potentially causing issues. #### Attribute Limits + - Span Attribute Count Limit: 256 - Log Attribute Count Limit: 256 - Span Attribute Value Length Limit: 1028 characters - Log Attribute Value Length Limit: 1028 characters #### Event and Link Limits + - Span Event Count Limit: 10 - Link Count Limit: 2 - Attributes per Link Limit: 10 - Attributes per Event Limit: 10 #### I/O Packet Length Limit + 128 KB (131,072 bytes) #### Attribute Clipping Behavior + - Attributes exceeding the value length limit (1028 characters) are discarded. - If the total number of attributes exceeds 256, additional attributes are not included. #### Attribute Value Size Calculation + - Strings: Actual length of the string - Numbers: 8 bytes - Booleans: 4 bytes @@ -93,25 +112,15 @@ We limit the size of logs to prevent oversized data potentially causing issues. -## Task payloads and outputs - -| Limit | Details | -|:--- |:--- | -| Single trigger payload | Must not exceed 10MB | -| Batch trigger payload | The total of all payloads must not exceed 10MB | -| Task outputs | Must not exceed 10MB | - -Payloads and outputs that exceed 512KB will be offloaded to object storage and a presigned URL will be provided to download the data when calling `runs.retrieve`. You don't need to do anything to handle this in your tasks however, as we will transparently upload/download these during operation. - ## Alerts An alert destination is a single email address, Slack channel, or webhook URL that you want to send alerts to. If you're on the Pro and need more than 100 alert destinations, you can request more by contacting us via [email](https://trigger.dev/contact) or [Discord](https://trigger.dev/discord). -| Pricing tier | Limit | -|:---------------- |:----------------------- | -| Free | 1 alert destination | -| Hobby | 3 alert destinations | -| Pro | 100+ alert destinations | +| Pricing tier | Limit | +| :----------- | :---------------------- | +| Free | 1 alert destination | +| Hobby | 3 alert destinations | +| Pro | 100+ alert destinations | ## Machines @@ -121,8 +130,8 @@ See the [machine configurations](/machines#machine-configurations) for more deta ## Team members -| Pricing tier | Limit | -|:---------------- |:----------------- | -| Free | 5 team members | -| Hobby | 5 team members | -| Pro | 25+ team members | +| Pricing tier | Limit | +| :----------- | :--------------- | +| Free | 5 team members | +| Hobby | 5 team members | +| Pro | 25+ team members | diff --git a/docs/triggering.mdx b/docs/triggering.mdx index 971d7c6806..5a20ed3d73 100644 --- a/docs/triggering.mdx +++ b/docs/triggering.mdx @@ -3,44 +3,38 @@ title: "Triggering" description: "Tasks need to be triggered in order to run." --- -Trigger tasks **from your backend**: - -| Function | This works | What it does | -| :----------------------- | :--------- | :-------------------------------------------------------------------------------------------------------------------------- | -| `tasks.trigger()` | Anywhere | Triggers a task and gets a handle you can use to fetch and manage the run. [Read more](#tasks-trigger) | -| `tasks.batchTrigger()` | Anywhere | Triggers a task multiple times and gets a handle you can use to fetch and manage the runs. [Read more](#tasks-batchtrigger) | -| `tasks.triggerAndPoll()` | Anywhere | Triggers a task and then polls the run until it’s complete. [Read more](#tasks-triggerandpoll) | - -Trigger tasks **from inside a run**: - -| Function | This works | What it does | -| :------------------------------- | :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `yourTask.trigger()` | Anywhere | Triggers a task and gets a handle you can use to monitor and manage the run. It does not wait for the result. [Read more](#yourtask-trigger) | -| `yourTask.batchTrigger()` | Anywhere | Triggers a task multiple times and gets a handle you can use to monitor and manage the runs. It does not wait for the results. [Read more](#yourtask-batchtrigger) | -| `yourTask.triggerAndWait()` | Inside task | Triggers a task and then waits until it's complete. You get the result data to continue with. [Read more](#yourtask-triggerandwait) | -| `yourTask.batchTriggerAndWait()` | Inside task | Triggers a task multiple times in parallel and then waits until they're all complete. You get the resulting data to continue with. [Read more](#yourtask-batchtriggerandwait) | - -Additionally, [scheduled tasks](/tasks/scheduled) get **automatically** triggered on their schedule and webhooks when receiving a webhook. - -## Scheduled tasks - -You should attach one or more schedules to your `schedules.task()` to trigger it on a recurring schedule. [Read the scheduled tasks docs](/tasks/scheduled). +## Trigger functions -## Authentication +Trigger tasks **from your backend**: -When you trigger a task from your backend code, you need to set the `TRIGGER_SECRET_KEY` environment variable. You can find the value on the API keys page in the Trigger.dev dashboard. [More info on API keys](/apikeys). +| Function | What it does | | +| :----------------------- | :----------------------------------------------------------------------------------------------- | ----------------------------- | +| `tasks.trigger()` | Triggers a task and returns a handle you can use to fetch and manage the run. | [Docs](#tasks-trigger) | +| `tasks.batchTrigger()` | Triggers a single task in a batch and returns a handle you can use to fetch and manage the runs. | [Docs](#tasks-batchtrigger) | +| `tasks.triggerAndPoll()` | Triggers a task and then polls the run until it’s complete. | [Docs](#tasks-triggerandpoll) | +| `batch.trigger()` | Similar to `tasks.batchTrigger` but allows running multiple different tasks | [Docs](#batch-trigger) | + +Trigger tasks **from inside a another task**: + +| Function | What it does | | +| :------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | +| `yourTask.trigger()` | Triggers a task and gets a handle you can use to monitor and manage the run. It does not wait for the result. | [Docs](#yourtask-trigger) | +| `yourTask.batchTrigger()` | Triggers a task multiple times and gets a handle you can use to monitor and manage the runs. It does not wait for the results. | [Docs](#yourtask-batchtrigger) | +| `yourTask.triggerAndWait()` | Triggers a task and then waits until it's complete. You get the result data to continue with. | [Docs](#yourtask-triggerandwait) | +| `yourTask.batchTriggerAndWait()` | Triggers a task multiple times in parallel and then waits until they're all complete. You get the resulting data to continue with. | [Docs](#yourtask-batchtriggerandwait) | +| `batch.triggerAndWait()` | Similar to `batch.trigger` but will wait on the triggered tasks to finish and return the results. | [Docs](#batch-triggerandwait) | +| `batch.triggerByTask()` | Similar to `batch.trigger` but allows passing in task instances instead of task IDs. | [Docs](#batch-triggerbytask) | +| `batch.triggerByTaskAndWait()` | Similar to `batch.triggerbyTask` but will wait on the triggered tasks to finish and return the results. | [Docs](#batch-triggerbytaskandwait) | ## Triggering from your backend -You can trigger any task from your backend code using the `tasks.trigger()` or `tasks.batchTrigger()` SDK functions. +When you trigger a task from your backend code, you need to set the `TRIGGER_SECRET_KEY` environment variable. You can find the value on the API keys page in the Trigger.dev dashboard. [More info on API keys](/apikeys). - Do not trigger tasks directly from your frontend. If you do, you will leak your private - Trigger.dev API key. + If you are using Next.js Server Actions [you'll need to be careful with + bundling](/guides/frameworks/nextjs#triggering-your-task-in-next-js). -You can use Next.js Server Actions but [you need to be careful with bundling](/guides/frameworks/nextjs#triggering-your-task-in-next-js). - ### tasks.trigger() Triggers a single run of a task with the payload you pass in, and any options you specify, without needing to import the task. @@ -51,9 +45,7 @@ Triggers a single run of a task with the payload you pass in, and any options yo application. - - -```ts Next.js API route +```ts Your backend import { tasks } from "@trigger.dev/sdk/v3"; import type { emailSequence } from "~/trigger/emails"; // πŸ‘† **type-only** import @@ -74,45 +66,37 @@ export async function POST(request: Request) { } ``` -```ts Remix +You can pass in options to the task using the second argument: + +```ts Your backend import { tasks } from "@trigger.dev/sdk/v3"; import type { emailSequence } from "~/trigger/emails"; -// πŸ‘† **type-only** import - -export async function action({ request, params }: ActionFunctionArgs) { - if (request.method !== "POST") { - throw new Response("Method Not Allowed", { status: 405 }); - } +//app/email/route.ts +export async function POST(request: Request) { //get the JSON from the request const data = await request.json(); // Pass the task type to `trigger()` as a generic argument, giving you full type checking - const handle = await tasks.trigger("email-sequence", { - to: data.email, - name: data.name, - }); + const handle = await tasks.trigger( + "email-sequence", + { + to: data.email, + name: data.name, + }, + { delay: "1h" } // πŸ‘ˆ Pass in the options here + ); //return a success response with the handle - return json(handle); + return Response.json(handle); } ``` - - ### tasks.batchTrigger() -Triggers multiple runs of a task with the payloads you pass in, and any options you specify, without needing to import the task. - - - By using `tasks.batchTrigger()`, you can pass in the task type as a generic argument, giving you - full type checking. Make sure you use a `type` import so that your task code is not imported into - your application. - - - +Triggers multiple runs of a single task with the payloads you pass in, and any options you specify, without needing to import the task. -```ts Next.js API route +```ts Your backend import { tasks } from "@trigger.dev/sdk/v3"; import type { emailSequence } from "~/trigger/emails"; // πŸ‘† **type-only** import @@ -133,44 +117,62 @@ export async function POST(request: Request) { } ``` -```ts Remix +You can pass in options to the `batchTrigger` function using the second argument: + +```ts Your backend import { tasks } from "@trigger.dev/sdk/v3"; import type { emailSequence } from "~/trigger/emails"; -export async function action({ request, params }: ActionFunctionArgs) { - if (request.method !== "POST") { - throw new Response("Method Not Allowed", { status: 405 }); - } - +//app/email/route.ts +export async function POST(request: Request) { //get the JSON from the request const data = await request.json(); // Pass the task type to `batchTrigger()` as a generic argument, giving you full type checking const batchHandle = await tasks.batchTrigger( "email-sequence", - data.users.map((u) => ({ payload: { to: u.email, name: u.name } })) + data.users.map((u) => ({ payload: { to: u.email, name: u.name } })), + { idempotencyKey: "my-idempotency-key" } // πŸ‘ˆ Pass in the options here ); //return a success response with the handle - return json(batchHandle); + return Response.json(batchHandle); } ``` - +You can also pass in options for each run in the batch: + +```ts Your backend +import { tasks } from "@trigger.dev/sdk/v3"; +import type { emailSequence } from "~/trigger/emails"; + +//app/email/route.ts +export async function POST(request: Request) { + //get the JSON from the request + const data = await request.json(); + + // Pass the task type to `batchTrigger()` as a generic argument, giving you full type checking + const batchHandle = await tasks.batchTrigger( + "email-sequence", + data.users.map((u) => ({ payload: { to: u.email, name: u.name }, options: { delay: "1h" } })) // πŸ‘ˆ Pass in options to each item like so + ); + + //return a success response with the handle + return Response.json(batchHandle); +} +``` ### tasks.triggerAndPoll() Triggers a single run of a task with the payload you pass in, and any options you specify, and then polls the run until it's complete. - - By using `tasks.triggerAndPoll()`, you can pass in the task type as a generic argument, giving you - full type checking. Make sure you use a `type` import so that your task code is not imported into - your application. - - - + + We don't recommend using `triggerAndPoll()`, especially inside a web request, as it will block the + request until the run is complete. Please see our [Realtime docs](/realtime) for a better way to + handle this. + -```ts Next.js API route +```ts Your backend import { tasks } from "@trigger.dev/sdk/v3"; import type { emailSequence } from "~/trigger/emails"; @@ -194,78 +196,127 @@ export async function POST(request: Request) { } ``` -```ts Remix -import { tasks } from "@trigger.dev/sdk/v3"; -import type { emailSequence } from "~/trigger/emails"; +### batch.trigger() -export async function action({ request, params }: ActionFunctionArgs) { - if (request.method !== "POST") { - throw new Response("Method Not Allowed", { status: 405 }); - } +Triggers multiple runs of different tasks with the payloads you pass in, and any options you specify. This is useful when you need to trigger multiple tasks at once. + +```ts Your backend +import { batch } from "@trigger.dev/sdk/v3"; +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 the task type to `triggerAndPoll()` as a generic argument, giving you full type checking - const result = await tasks.triggerAndPoll( - "email-sequence", - { - to: data.email, - name: data.name, - }, - { pollIntervalMs: 5000 } - ); + // Pass a union of the tasks to `trigger()` as a generic argument, giving you full type checking + const result = await batch.trigger([ + // Because we're using a union, we can pass in multiple tasks by ID + { id: "my-task-1", payload: { some: data.some } }, + { id: "my-task-2", payload: { other: data.other } }, + ]); //return a success response with the result - return json(result); + return Response.json(result); } ``` - +## Triggering from inside another task + +The following functions should only be used when running inside a task, for one of the following reasons: + +- You need to **wait** for the result of the triggered task. +- You need to import the task instance. Importing a task instance from your backend code is not recommended, as it can pull in a lot of unnecessary code and dependencies. + +### yourTask.trigger() + +Triggers a single run of a task with the payload you pass in, and any options you specify. - The above code is just a demonstration of the API and is not recommended to use in an API route - this way as it will block the request until the task is complete. + If you need to call `trigger()` on a task in a loop, use + [`batchTrigger()`](#yourTask-batchtrigger) instead which will trigger up to 500 runs in a single + call. -## Triggering from inside a run +```ts ./trigger/my-task.ts +import { myOtherTask, runs } from "~/trigger/my-other-task"; -Task instance methods are available on the `Task` object you receive when you define a task. We recommend you use these methods inside another task to trigger subtasks. +export const myTask = task({ + id: "my-task", + run: async (payload: string) => { + const handle = await myOtherTask.trigger({ foo: "some data" }); -### yourTask.trigger() + const run = await runs.retrieve(handle); + // Do something with the run + }, +}); +``` -Triggers a single run of a task with the payload you pass in, and any options you specify. It does NOT wait for the result. +To pass options to the triggered task, you can use the second argument: -If called from within a task, you can use the `AndWait` version to pause execution until the triggered run is complete. +```ts ./trigger/my-task.ts +import { myOtherTask, runs } from "~/trigger/my-other-task"; -If you need to call `trigger()` on a task in a loop, use [`batchTrigger()`](/triggering#task-batchtrigger) instead which will trigger up to 100 tasks in a single call. +export const myTask = task({ + id: "my-task", + run: async (payload: string) => { + const handle = await myOtherTask.trigger({ foo: "some data" }, { delay: "1h" }); + + const run = await runs.retrieve(handle); + // Do something with the run + }, +}); +``` + +### yourTask.batchTrigger() + +Triggers multiple runs of a single task with the payloads you pass in, and any options you specify. ```ts /trigger/my-task.ts -import { myOtherTask } from "~/trigger/my-other-task"; +import { myOtherTask, batch } from "~/trigger/my-other-task"; export const myTask = task({ id: "my-task", run: async (payload: string) => { - const handle = await myOtherTask.trigger("some data"); + const batchHandle = await myOtherTask.batchTrigger([{ payload: "some data" }]); //...do other stuff + const batch = await batch.retrieve(batchHandle.id); }, }); ``` -### yourTask.batchTrigger() +If you need to pass options to `batchTrigger`, you can use the second argument: -Triggers multiple runs of a task with the payloads you pass in, and any options you specify. It does NOT wait for the result. +```ts /trigger/my-task.ts +import { myOtherTask, batch } from "~/trigger/my-other-task"; + +export const myTask = task({ + id: "my-task", + run: async (payload: string) => { + const batchHandle = await myOtherTask.batchTrigger([{ payload: "some data" }], { + idempotencyKey: "my-task-key", + }); + + //...do other stuff + const batch = await batch.retrieve(batchHandle.id); + }, +}); +``` + +You can also pass in options for each run in the batch: ```ts /trigger/my-task.ts -import { myOtherTask } from "~/trigger/my-other-task"; +import { myOtherTask, batch } from "~/trigger/my-other-task"; export const myTask = task({ id: "my-task", run: async (payload: string) => { - const batchHandle = await myOtherTask.batchTrigger([{ payload: "some data" }]); + const batchHandle = await myOtherTask.batchTrigger([ + { payload: "some data", options: { delay: "1h" } }, + ]); //...do other stuff + const batch = await batch.retrieve(batchHandle.id); }, }); ``` @@ -504,6 +555,152 @@ export const batchParentTask = task({ error. +### batch.triggerAndWait() + +You can batch trigger multiple different tasks and wait for all the results: + +```ts /trigger/batch.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([ + { 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: + +```ts /trigger/batch.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() + +You can batch trigger multiple different tasks by passing in the task instances, and wait for all the results. This function is especially useful when you have a static set of tasks you want to trigger: + +```ts /trigger/batch.ts +import { batch, task, runs } from "@trigger.dev/sdk/v3"; + +export const parentTask = task({ + id: "parent-task", + run: async (payload: string) => { + const { runs } = await batch.triggerByTaskAndWait([ + { 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 + ]); + + if (runs[0].ok) { + console.log("Child task 1 output", runs[0].output); // πŸ‘ˆ runs[0].output is typed as the output of childTask1 + } + + if (runs[1].ok) { + console.log("Child task 2 output", runs[1].output); // πŸ‘ˆ runs[1].output is typed as the output of childTask2 + } + + // πŸ’­ A nice alternative syntax is to destructure the runs array: + const { + runs: [run1, run2], + } = await batch.triggerByTaskAndWait([ + { 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 + ]); + + if (run1.ok) { + console.log("Child task 1 output", run1.output); // πŸ‘ˆ run1.output is typed as the output of childTask1 + } + + if (run2.ok) { + console.log("Child task 2 output", run2.output); // πŸ‘ˆ run2.output 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; + }, +}); +``` + +## Triggering from your frontend + +If you want to trigger a task directly from a frontend application, you can use our [React +hooks](/frontend/react-hooks#trigger-hooks). + ## Options All of the above functions accept an options object: @@ -623,7 +820,39 @@ export const myTask = task({ const idempotencyKey = await idempotencyKeys.create("my-task-key"); // childTask will only be triggered once with the same idempotency key - await childTask.triggerAndWait(payload, { idempotencyKey }); + await childTask.trigger(payload, { idempotencyKey }); + + // Do something else, that may throw an error and cause the task to be retried + }, +}); +``` + +For more information, see our [Idempotency](/idempotency) documentation. + + + In version 3.3.0 and later, the `idempotencyKey` option is not available when using + `triggerAndWait` or `batchTriggerAndWait`, due to a bug that would sometimes cause the parent task + to become stuck. We are working on a fix for this issue. + + +### `idempotencyKeyTTL` + +Idempotency keys automatically expire after 30 days, but you can set a custom TTL for an idempotency key when triggering a task: + +```typescript +import { idempotencyKeys, task } from "@trigger.dev/sdk/v3"; + +export const myTask = task({ + id: "my-task", + retry: { + maxAttempts: 4, + }, + run: async (payload: any) => { + // By default, idempotency keys generated are unique to the run, to prevent retries from duplicating child tasks + const idempotencyKey = await idempotencyKeys.create("my-task-key"); + + // childTask will only be triggered once with the same idempotency key + await childTask.trigger(payload, { idempotencyKey, idempotencyKeyTTL: "1h" }); // Do something else, that may throw an error and cause the task to be retried }, @@ -827,4 +1056,4 @@ export const myTask = task({ ### Batch Triggering -When using `batchTrigger` or `batchTriggerAndWait`, the total size of all payloads cannot exceed 10MB. This means if you are doing a batch of 100 runs, each payload should be less than 100KB. +When using triggering a batch, the total size of all payloads cannot exceed 1MB. This means if you are doing a batch of 100 runs, each payload should be less than 100KB. From 011ecc5a02f8e08a3c38702e0837286820ef81df Mon Sep 17 00:00:00 2001 From: Eric Allam Date: Thu, 28 Nov 2024 11:28:46 +0000 Subject: [PATCH 2/2] More batch trigger v2 docs --- docs/guides/examples/scrape-hacker-news.mdx | 37 ++--- docs/idempotency.mdx | 66 +++++++-- docs/mint.json | 3 +- docs/realtime/subscribe-to-batch.mdx | 49 +++++++ docs/runs.mdx | 146 +++++++++++++++++--- docs/triggering.mdx | 2 +- docs/v3-openapi.yaml | 8 +- 7 files changed, 250 insertions(+), 61 deletions(-) create mode 100644 docs/realtime/subscribe-to-batch.mdx diff --git a/docs/guides/examples/scrape-hacker-news.mdx b/docs/guides/examples/scrape-hacker-news.mdx index 467a7f955e..837a92ea50 100644 --- a/docs/guides/examples/scrape-hacker-news.mdx +++ b/docs/guides/examples/scrape-hacker-news.mdx @@ -8,7 +8,16 @@ import LocalDevelopment from "/snippets/local-development-extensions.mdx"; import ScrapingWarning from "/snippets/web-scraping-warning.mdx";
-