Skip to content

Commit a0f8f80

Browse files
committed
More batch trigger v2 docs
1 parent 059fbf5 commit a0f8f80

File tree

7 files changed

+250
-61
lines changed

7 files changed

+250
-61
lines changed

docs/guides/examples/scrape-hacker-news.mdx

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,16 @@ import LocalDevelopment from "/snippets/local-development-extensions.mdx";
88
import ScrapingWarning from "/snippets/web-scraping-warning.mdx";
99

1010
<div className="w-full h-full aspect-video">
11-
<iframe width="100%" height="100%" src="https://www.youtube.com/embed/6azvzrZITKY?si=muKtsBiS9TJGGKWg" title="YouTube video player" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen/>
11+
<iframe
12+
width="100%"
13+
height="100%"
14+
src="https://www.youtube.com/embed/6azvzrZITKY?si=muKtsBiS9TJGGKWg"
15+
title="YouTube video player"
16+
frameborder="0"
17+
allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
18+
referrerpolicy="strict-origin-when-cross-origin"
19+
allowfullscreen
20+
/>
1221
</div>
1322

1423
## Overview
@@ -125,12 +134,9 @@ export const summarizeHackerNews = schedules.task({
125134
.batchTriggerAndWait(
126135
articles.map((article) => ({
127136
payload: { title: article.title!, link: article.link! },
128-
idempotencyKey: article.link,
129137
}))
130138
)
131-
.then((batch) =>
132-
batch.runs.filter((run) => run.ok).map((run) => run.output)
133-
);
139+
.then((batch) => batch.runs.filter((run) => run.ok).map((run) => run.output));
134140

135141
// Send email using Resend
136142
await resend.emails.send({
@@ -165,11 +171,7 @@ export const scrapeAndSummarizeArticle = task({
165171
// Prevent all assets from loading, images, stylesheets etc
166172
await page.setRequestInterception(true);
167173
page.on("request", (request) => {
168-
if (
169-
["script", "stylesheet", "image", "media", "font"].includes(
170-
request.resourceType()
171-
)
172-
) {
174+
if (["script", "stylesheet", "image", "media", "font"].includes(request.resourceType())) {
173175
request.abort();
174176
} else {
175177
request.continue();
@@ -218,26 +220,15 @@ To prevent the main example from becoming too cluttered, we'll create a separate
218220
Notice how this file is imported into the main task code and passed to Resend to send the email.
219221

220222
```tsx summarize-hn-email.tsx
221-
import {
222-
Html,
223-
Head,
224-
Body,
225-
Container,
226-
Section,
227-
Heading,
228-
Text,
229-
Link,
230-
} from "@react-email/components";
223+
import { Html, Head, Body, Container, Section, Heading, Text, Link } from "@react-email/components";
231224

232225
interface Article {
233226
title: string;
234227
link: string;
235228
summary: string | null;
236229
}
237230

238-
export const HNSummaryEmail: React.FC<{ articles: Article[] }> = ({
239-
articles,
240-
}) => (
231+
export const HNSummaryEmail: React.FC<{ articles: Article[] }> = ({ articles }) => (
241232
<Html>
242233
<Head />
243234
<Body style={{ fontFamily: "Arial, sans-serif", padding: "20px" }}>

docs/idempotency.mdx

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@ description: "An API call or operation is “idempotent” if it has the same re
55

66
We currently support idempotency at the task level, meaning that if you trigger a task with the same `idempotencyKey` twice, the second request will not create a new task run.
77

8+
<Warning>
9+
In version 3.3.0 and later, the `idempotencyKey` option is not available when using
10+
`triggerAndWait` or `batchTriggerAndWait`, due to a bug that would sometimes cause the parent task
11+
to become stuck. We are working on a fix for this issue.
12+
</Warning>
13+
814
## `idempotencyKey` option
915

1016
You can provide an `idempotencyKey` to ensure that a task is only triggered once with the same key. This is useful if you are triggering a task within another task that might be retried:
1117

12-
```typescript
18+
```ts
1319
import { idempotencyKeys, task } from "@trigger.dev/sdk/v3";
1420

1521
export const myTask = task({
@@ -18,13 +24,14 @@ export const myTask = task({
1824
maxAttempts: 4,
1925
},
2026
run: async (payload: any) => {
21-
// By default, idempotency keys generated are unique to the run, to prevent retries from duplicating child tasks
27+
// This idempotency key will be unique to this task run, meaning the childTask will only be triggered once across all retries
2228
const idempotencyKey = await idempotencyKeys.create("my-task-key");
2329

2430
// childTask will only be triggered once with the same idempotency key
25-
await childTask.triggerAndWait(payload, { idempotencyKey });
31+
await childTask.trigger({ foo: "bar" }, { idempotencyKey });
2632

2733
// Do something else, that may throw an error and cause the task to be retried
34+
throw new Error("Something went wrong");
2835
},
2936
});
3037
```
@@ -33,7 +40,7 @@ You can use the `idempotencyKeys.create` SDK function to create an idempotency k
3340

3441
We automatically inject the run ID when generating the idempotency key when running inside a task by default. You can turn it off by passing the `scope` option to `idempotencyKeys.create`:
3542

36-
```typescript
43+
```ts
3744
import { idempotencyKeys, task } from "@trigger.dev/sdk/v3";
3845

3946
export const myTask = task({
@@ -42,21 +49,18 @@ export const myTask = task({
4249
maxAttempts: 4,
4350
},
4451
run: async (payload: any) => {
45-
// This idempotency key will be the same for all runs of this task
52+
// This idempotency key will be globally unique, meaning only a single task run will be triggered with this key
4653
const idempotencyKey = await idempotencyKeys.create("my-task-key", { scope: "global" });
4754

4855
// childTask will only be triggered once with the same idempotency key
49-
await childTask.triggerAndWait(payload, { idempotencyKey });
50-
51-
// This is the same as the above
52-
await childTask.triggerAndWait(payload, { idempotencyKey: "my-task-key" });
56+
await childTask.trigger({ foo: "bar" }, { idempotencyKey });
5357
},
5458
});
5559
```
5660

5761
If you are triggering a task from your backend code, you can use the `idempotencyKeys.create` SDK function to create an idempotency key.
5862

59-
```typescript
63+
```ts
6064
import { idempotencyKeys, tasks } from "@trigger.dev/sdk/v3";
6165

6266
// You can also pass an array of strings to create a idempotency key
@@ -66,7 +70,7 @@ await tasks.trigger("my-task", { some: "data" }, { idempotencyKey });
6670

6771
You can also pass a string to the `idempotencyKey` option, without first creating it with `idempotencyKeys.create`.
6872

69-
```typescript
73+
```ts
7074
import { myTask } from "./trigger/myTasks";
7175

7276
// You can also pass an array of strings to create a idempotency key
@@ -77,7 +81,7 @@ await myTask.trigger({ some: "data" }, { idempotencyKey: myUser.id });
7781

7882
You can pass the `idempotencyKey` when calling `batchTrigger` as well:
7983

80-
```typescript
84+
```ts
8185
import { tasks } from "@trigger.dev/sdk/v3";
8286

8387
await tasks.batchTrigger("my-task", [
@@ -88,11 +92,47 @@ await tasks.batchTrigger("my-task", [
8892
]);
8993
```
9094

95+
## `idempotencyKeyTTL` option
96+
97+
By default idempotency keys are stored for 30 days. You can change this by passing the `idempotencyKeyTTL` option when triggering a task:
98+
99+
```ts
100+
import { idempotencyKeys, task, wait } from "@trigger.dev/sdk/v3";
101+
102+
export const myTask = task({
103+
id: "my-task",
104+
retry: {
105+
maxAttempts: 4,
106+
},
107+
run: async (payload: any) => {
108+
const idempotencyKey = await idempotencyKeys.create("my-task-key");
109+
110+
// The idempotency key will expire after 60 seconds
111+
await childTask.trigger({ foo: "bar" }, { idempotencyKey, idempotencyKeyTTL: "60s" });
112+
113+
await wait.for({ seconds: 61 });
114+
115+
// The idempotency key will have expired, so the childTask will be triggered again
116+
await childTask.trigger({ foo: "bar" }, { idempotencyKey });
117+
118+
// Do something else, that may throw an error and cause the task to be retried
119+
throw new Error("Something went wrong");
120+
},
121+
});
122+
```
123+
124+
You can use the following units for the `idempotencyKeyTTL` option:
125+
126+
- `s` for seconds (e.g. `60s`)
127+
- `m` for minutes (e.g. `5m`)
128+
- `h` for hours (e.g. `2h`)
129+
- `d` for days (e.g. `3d`)
130+
91131
## Payload-based idempotency
92132

93133
We don't currently support payload-based idempotency, but you can implement it yourself by hashing the payload and using the hash as the idempotency key.
94134

95-
```typescript
135+
```ts
96136
import { idempotencyKeys, task } from "@trigger.dev/sdk/v3";
97137
import { createHash } from "node:crypto";
98138

docs/mint.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@
217217
"realtime/streams",
218218
"realtime/react-hooks",
219219
"realtime/subscribe-to-run",
220-
"realtime/subscribe-to-runs-with-tag"
220+
"realtime/subscribe-to-runs-with-tag",
221+
"realtime/subscribe-to-batch"
221222
]
222223
},
223224
{

docs/realtime/subscribe-to-batch.mdx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: runs.subscribeToBatch
3+
sidebarTitle: subscribeToBatch
4+
description: Subscribes to all changes for runs in a batch.
5+
---
6+
7+
import RunObject from "/snippets/realtime/run-object.mdx";
8+
9+
<RequestExample>
10+
11+
```ts Example
12+
import { runs } from "@trigger.dev/sdk/v3";
13+
14+
for await (const run of runs.subscribeToBatch("batch_1234")) {
15+
console.log(run);
16+
}
17+
```
18+
19+
</RequestExample>
20+
21+
This function subscribes to all changes for runs in a batch. It returns an async iterator that yields the a run object whenever a run in the batch is updated. The iterator does not complete on it's own, you must manually `break` the loop when you want to stop listening for updates.
22+
23+
### Authentication
24+
25+
This function supports both server-side and client-side authentication. For server-side authentication, use your API key. For client-side authentication, you must generate a public access token with one of the following scopes:
26+
27+
- `read:batch:<batchId>`
28+
- `read:runs` will provide access to all runs (not recommended for production use)
29+
30+
To generate a public access token, use the `auth.createPublicToken` function:
31+
32+
```ts
33+
import { auth } from "@trigger.dev/sdk/v3";
34+
35+
// Somewhere in your backend code
36+
const publicToken = await auth.createPublicToken({
37+
scopes: {
38+
read: {
39+
batch: ["batch_1234"],
40+
},
41+
},
42+
});
43+
```
44+
45+
### Response
46+
47+
The AsyncIterator yields an object with the following properties:
48+
49+
<RunObject />

0 commit comments

Comments
 (0)