Skip to content

Commit f3faf3b

Browse files
committed
chore: merge main into release for new releases
2 parents 5bc8818 + 7bebdd5 commit f3faf3b

File tree

11 files changed

+1771
-3
lines changed

11 files changed

+1771
-3
lines changed

.cursor/rules/trigger.advanced-tasks.mdc

Lines changed: 456 additions & 0 deletions
Large diffs are not rendered by default.

.cursor/rules/trigger.basic.mdc

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
---
2+
description: Only the most important rules for writing basic Trigger.dev tasks
3+
globs: **/trigger/**/*.ts
4+
alwaysApply: false
5+
---
6+
# Trigger.dev Basic Tasks (v4)
7+
8+
**MUST use `@trigger.dev/sdk` (v4), NEVER `client.defineJob`**
9+
10+
## Basic Task
11+
12+
```ts
13+
import { task } from "@trigger.dev/sdk";
14+
15+
export const processData = task({
16+
id: "process-data",
17+
retry: {
18+
maxAttempts: 10,
19+
factor: 1.8,
20+
minTimeoutInMs: 500,
21+
maxTimeoutInMs: 30_000,
22+
randomize: false,
23+
},
24+
run: async (payload: { userId: string; data: any[] }) => {
25+
// Task logic - runs for long time, no timeouts
26+
console.log(`Processing ${payload.data.length} items for user ${payload.userId}`);
27+
return { processed: payload.data.length };
28+
},
29+
});
30+
```
31+
32+
## Schema Task (with validation)
33+
34+
```ts
35+
import { schemaTask } from "@trigger.dev/sdk";
36+
import { z } from "zod";
37+
38+
export const validatedTask = schemaTask({
39+
id: "validated-task",
40+
schema: z.object({
41+
name: z.string(),
42+
age: z.number(),
43+
email: z.string().email(),
44+
}),
45+
run: async (payload) => {
46+
// Payload is automatically validated and typed
47+
return { message: `Hello ${payload.name}, age ${payload.age}` };
48+
},
49+
});
50+
```
51+
52+
## Scheduled Task
53+
54+
```ts
55+
import { schedules } from "@trigger.dev/sdk";
56+
57+
const dailyReport = schedules.task({
58+
id: "daily-report",
59+
cron: "0 9 * * *", // Daily at 9:00 AM UTC
60+
// or with timezone: cron: { pattern: "0 9 * * *", timezone: "America/New_York" },
61+
run: async (payload) => {
62+
console.log("Scheduled run at:", payload.timestamp);
63+
console.log("Last run was:", payload.lastTimestamp);
64+
console.log("Next 5 runs:", payload.upcoming);
65+
66+
// Generate daily report logic
67+
return { reportGenerated: true, date: payload.timestamp };
68+
},
69+
});
70+
```
71+
72+
## Triggering Tasks
73+
74+
### From Backend Code
75+
76+
```ts
77+
import { tasks } from "@trigger.dev/sdk";
78+
import type { processData } from "./trigger/tasks";
79+
80+
// Single trigger
81+
const handle = await tasks.trigger<typeof processData>("process-data", {
82+
userId: "123",
83+
data: [{ id: 1 }, { id: 2 }],
84+
});
85+
86+
// Batch trigger
87+
const batchHandle = await tasks.batchTrigger<typeof processData>("process-data", [
88+
{ payload: { userId: "123", data: [{ id: 1 }] } },
89+
{ payload: { userId: "456", data: [{ id: 2 }] } },
90+
]);
91+
```
92+
93+
### From Inside Tasks (with Result handling)
94+
95+
```ts
96+
export const parentTask = task({
97+
id: "parent-task",
98+
run: async (payload) => {
99+
// Trigger and continue
100+
const handle = await childTask.trigger({ data: "value" });
101+
102+
// Trigger and wait - returns Result object, NOT task output
103+
const result = await childTask.triggerAndWait({ data: "value" });
104+
if (result.ok) {
105+
console.log("Task output:", result.output); // Actual task return value
106+
} else {
107+
console.error("Task failed:", result.error);
108+
}
109+
110+
// Quick unwrap (throws on error)
111+
const output = await childTask.triggerAndWait({ data: "value" }).unwrap();
112+
113+
// Batch trigger and wait
114+
const results = await childTask.batchTriggerAndWait([
115+
{ payload: { data: "item1" } },
116+
{ payload: { data: "item2" } },
117+
]);
118+
119+
for (const run of results) {
120+
if (run.ok) {
121+
console.log("Success:", run.output);
122+
} else {
123+
console.log("Failed:", run.error);
124+
}
125+
}
126+
},
127+
});
128+
129+
export const childTask = task({
130+
id: "child-task",
131+
run: async (payload: { data: string }) => {
132+
return { processed: payload.data };
133+
},
134+
});
135+
```
136+
137+
> Never wrap triggerAndWait or batchTriggerAndWait calls in a Promise.all or Promise.allSettled as this is not supported in Trigger.dev tasks.
138+
139+
## Waits
140+
141+
```ts
142+
import { task, wait } from "@trigger.dev/sdk";
143+
144+
export const taskWithWaits = task({
145+
id: "task-with-waits",
146+
run: async (payload) => {
147+
console.log("Starting task");
148+
149+
// Wait for specific duration
150+
await wait.for({ seconds: 30 });
151+
await wait.for({ minutes: 5 });
152+
await wait.for({ hours: 1 });
153+
await wait.for({ days: 1 });
154+
155+
// Wait until specific date
156+
await wait.until({ date: new Date("2024-12-25") });
157+
158+
// Wait for token (from external system)
159+
await wait.forToken({
160+
token: "user-approval-token",
161+
timeoutInSeconds: 3600, // 1 hour timeout
162+
});
163+
164+
console.log("All waits completed");
165+
return { status: "completed" };
166+
},
167+
});
168+
```
169+
170+
> Never wrap wait calls in a Promise.all or Promise.allSettled as this is not supported in Trigger.dev tasks.
171+
172+
## Key Points
173+
174+
- **Result vs Output**: `triggerAndWait()` returns a `Result` object with `ok`, `output`, `error` properties - NOT the direct task output
175+
- **Type safety**: Use `import type` for task references when triggering from backend
176+
- **Waits > 5 seconds**: Automatically checkpointed, don't count toward compute usage
177+
178+
## NEVER Use (v2 deprecated)
179+
180+
```ts
181+
// BREAKS APPLICATION
182+
client.defineJob({
183+
id: "job-id",
184+
run: async (payload, io) => {
185+
/* ... */
186+
},
187+
});
188+
```
189+
190+
Use v4 SDK (`@trigger.dev/sdk`), check `result.ok` before accessing `result.output`

0 commit comments

Comments
 (0)