118 lines
2.8 KiB
Markdown
118 lines
2.8 KiB
Markdown
# Scheduled tasks (cron)
|
||
|
||
Recurring tasks using cron. For one-off future runs, use the **delay** option.
|
||
|
||
## Define a scheduled task
|
||
|
||
```ts
|
||
import { schedules } from "@trigger.dev/sdk";
|
||
|
||
export const task = schedules.task({
|
||
id: "first-scheduled-task",
|
||
run: async (payload) => {
|
||
payload.timestamp; // Date (scheduled time, UTC)
|
||
payload.lastTimestamp; // Date | undefined
|
||
payload.timezone; // IANA, e.g. "America/New_York" (default "UTC")
|
||
payload.scheduleId; // string
|
||
payload.externalId; // string | undefined
|
||
payload.upcoming; // Date[]
|
||
|
||
payload.timestamp.toLocaleString("en-US", { timeZone: payload.timezone });
|
||
},
|
||
});
|
||
```
|
||
|
||
> Scheduled tasks need at least one schedule attached to run.
|
||
|
||
## Attach schedules
|
||
|
||
**Declarative (sync on dev/deploy):**
|
||
|
||
```ts
|
||
schedules.task({
|
||
id: "every-2h",
|
||
cron: "0 */2 * * *", // UTC
|
||
run: async () => {},
|
||
});
|
||
|
||
schedules.task({
|
||
id: "tokyo-5am",
|
||
cron: { pattern: "0 5 * * *", timezone: "Asia/Tokyo", environments: ["PRODUCTION", "STAGING"] },
|
||
run: async () => {},
|
||
});
|
||
```
|
||
|
||
**Imperative (SDK or dashboard):**
|
||
|
||
```ts
|
||
await schedules.create({
|
||
task: task.id,
|
||
cron: "0 0 * * *",
|
||
timezone: "America/New_York", // DST-aware
|
||
externalId: "user_123",
|
||
deduplicationKey: "user_123-daily", // updates if reused
|
||
});
|
||
```
|
||
|
||
### Dynamic / multi-tenant example
|
||
|
||
```ts
|
||
// /trigger/reminder.ts
|
||
export const reminderTask = schedules.task({
|
||
id: "todo-reminder",
|
||
run: async (p) => {
|
||
if (!p.externalId) throw new Error("externalId is required");
|
||
const user = await db.getUser(p.externalId);
|
||
await sendReminderEmail(user);
|
||
},
|
||
});
|
||
```
|
||
|
||
```ts
|
||
// app/reminders/route.ts
|
||
export async function POST(req: Request) {
|
||
const data = await req.json();
|
||
return Response.json(
|
||
await schedules.create({
|
||
task: reminderTask.id,
|
||
cron: "0 8 * * *",
|
||
timezone: data.timezone,
|
||
externalId: data.userId,
|
||
deduplicationKey: `${data.userId}-reminder`,
|
||
})
|
||
);
|
||
}
|
||
```
|
||
|
||
## Cron syntax (no seconds)
|
||
|
||
```
|
||
* * * * *
|
||
| | | | └ day of week (0–7 or 1L–7L; 0/7=Sun; L=last)
|
||
| | | └── month (1–12)
|
||
| | └──── day of month (1–31 or L)
|
||
| └────── hour (0–23)
|
||
└──────── minute (0–59)
|
||
```
|
||
|
||
## When schedules won't trigger
|
||
|
||
- **Dev:** only when the dev CLI is running.
|
||
- **Staging/Production:** only for tasks in the **latest deployment**.
|
||
|
||
## SDK management (quick refs)
|
||
|
||
```ts
|
||
await schedules.retrieve(id);
|
||
await schedules.list();
|
||
await schedules.update(id, { cron: "0 0 1 * *", externalId: "ext", deduplicationKey: "key" });
|
||
await schedules.deactivate(id);
|
||
await schedules.activate(id);
|
||
await schedules.del(id);
|
||
await schedules.timezones(); // list of IANA timezones
|
||
```
|
||
|
||
## Dashboard
|
||
|
||
Create/attach schedules visually (Task, Cron pattern, Timezone, Optional: External ID, Dedup key, Environments). Test scheduled tasks from the **Test** page.
|