spinny:~/writing $ less trigger-dev-background-jobs-guide.md
12Hau het cac ung dung production deu can cong viec khong vua voi chu ky request/response: gui email, xu ly upload, chay AI pipeline, dong bo du lieu ben thu ba, tao bao cao. Cau tra loi truyen thong la mot queue (Redis, SQS, RabbitMQ), mot doi worker, mot scheduler va mot dong code keo dan mong manh bi vo o moi lan deploy.34[Trigger.dev](https://trigger.dev) thu gon stack do thanh mot SDK TypeScript duy nhat. Ban viet cac function, goi chung tu bat ky dau, va nen tang xu ly queueing, retries, observability, lap lich va thuc thi ben vung. Tasks chay bao lau tuy can - khong co timeout serverless 10 giay, khong mat cong viec khi redeploy.56## Tai sao Trigger.dev78Su thay doi nam 2026 la thuc thi ben vung. Workflow phai song sot qua khoi dong lai, su co, deploy va rate limit. Chung cung phai stream tien trinh den UI theo thoi gian thuc va tam dung de nhan input cua con nguoi. Trigger.dev duoc xay dung lai xung quanh nhung yeu cau nay voi phien ban 3 va tiep tuc mo rong be mat ha tang AI.910```mermaid11graph LR12 App[App cua ban] -->|trigger| API[Trigger.dev API]13 API --> Queue[Queue ben vung]14 Queue --> Worker[Container Worker]15 Worker -->|run task| Task[Code Task cua ban]16 Task -->|metadata| Realtime[Stream Realtime]17 Realtime --> UI[React UI]18 Worker --> Storage[Store Trang thai Run]19```2021Mo hinh don gian: ban dinh nghia tasks la exports, SDK chon chung, nen tang lap lich va chay chung trong cac container co lap, va trang thai run duoc giu lai de ban co the tiep tuc, thu lai va quan sat.2223## Bat dau2425### Khoi tao mot du an2627```bash28npx trigger.dev@latest login29npx trigger.dev@latest init30```3132Dieu nay tao mot tep `trigger.config.ts` va mot thu muc `trigger/` voi tasks vi du. Tep config la nguon su that cho du an cua ban: thu muc nao chua tasks, cai dat build, lifecycle hooks va tuy chon runtime.3334```typescript35// trigger.config.ts36import { defineConfig } from "@trigger.dev/sdk";3738export default defineConfig({39 project: "proj_abc123",40 runtime: "node",41 logLevel: "log",42 maxDuration: 3600,43 retries: {44 enabledInDev: true,45 default: {46 maxAttempts: 3,47 factor: 2,48 minTimeoutInMs: 1000,49 maxTimeoutInMs: 30_000,50 },51 },52 dirs: ["./trigger"],53});54```5556### Chay tasks tai dia phuong5758```bash59npx trigger.dev@latest dev60```6162Server dev ket noi voi cloud, dang ky tasks cua ban, va stream runs qua code dia phuong cua ban. Ban dat breakpoint trong editor cua minh va dat den chung tren cac trigger thuc te - cung mot vong lap ma ban se su dung trong bat ky du an Node.js binh thuong nao.6364## Dinh nghia mot Task6566Task la mot doi tuong duoc xuat voi mot `id` duy nhat va mot ham `run`. SDK kiem tra cac xuat trong `dirs` va dang ky chung tu dong.6768```typescript69// trigger/send-welcome-email.ts70import { task } from "@trigger.dev/sdk";71import { Resend } from "resend";7273const resend = new Resend(process.env.RESEND_API_KEY);7475export const sendWelcomeEmail = task({76 id: "send-welcome-email",77 retry: {78 maxAttempts: 5,79 factor: 1.8,80 minTimeoutInMs: 500,81 maxTimeoutInMs: 30_000,82 },83 run: async (payload: { email: string; name: string }) => {84 const { data, error } = await resend.emails.send({85 from: "hello@spinny.dev",86 to: payload.email,87 subject: `Welcome, ${payload.name}`,88 html: `<p>Glad you are here, ${payload.name}.</p>`,89 });9091 if (error) throw error;92 return { messageId: data?.id };93 },94});95```9697Ba dieu can chu y:98991. **Khong co timeout trong than run.** Nen tang quan ly thoi gian thuc thi qua `maxDuration` trong config, khong phai trong runtime.1002. **Throws la retries.** SDK bat exception va chay lai voi exponential backoff theo chinh sach `retry`.1013. **Gia tri tra ve duoc giu lai.** Cac tasks khac va frontend cua ban co the doc `run.output` tu bat ky dau.102103## Trigger Tasks104105Ban goi mot task tu backend, route API hoac task khac.106107```typescript108import { sendWelcomeEmail } from "@/trigger/send-welcome-email";109110const handle = await sendWelcomeEmail.trigger(111 { email: "user@example.com", name: "Alex" },112 {113 idempotencyKey: `welcome-${userId}`,114 concurrencyKey: `tenant-${tenantId}`,115 queue: { name: "emails", concurrencyLimit: 50 },116 delay: "30s",117 ttl: "10m",118 }119);120121console.log(handle.id); // run_xyz - su dung de theo doi hoac hien thi tien trinh122```123124Cac tuy chon mo khoa nhieu hanh vi trong mot lenh goi:125126- **`idempotencyKey`** - neu mot run voi cung key da ton tai, SDK tra ve handle hien co thay vi nhan ban cong viec.127- **`concurrencyKey`** - tuan tu hoa cac runs chia se key de ban khong vuot qua rate limit moi tenant.128- **`queue.concurrencyLimit`** - cap toan cau cho queue tren tat ca cac key.129- **`delay`** - lap lich run cho mot thoi diem trong tuong lai.130- **`ttl`** - neu run chua bat dau vao thoi diem do, het han tu dong.131132### Batch trigger133134Cho cac workload fan-out, `batchTrigger` chap nhan toi 500 muc moi cuoc goi va tao mot run moi muc.135136```typescript137await sendWelcomeEmail.batchTrigger(138 newUsers.map((u) => ({139 payload: { email: u.email, name: u.name },140 options: { idempotencyKey: `welcome-${u.id}` },141 }))142);143```144145## Tasks lap lich146147Cron jobs tro thanh khai bao hang nhat. Schedule la mot doi tuong rieng biet ma ban co the gan vao mot task nhieu lan.148149```typescript150// trigger/daily-digest.ts151import { schedules } from "@trigger.dev/sdk";152153export const dailyDigest = schedules.task({154 id: "daily-digest",155 cron: "0 9 * * *",156 run: async (payload) => {157 console.log("Scheduled at:", payload.timestamp);158 console.log("Last run:", payload.lastTimestamp);159 console.log("Timezone:", payload.timezone);160 console.log("Next 5 runs:", payload.upcoming);161162 await sendDigestForDate(payload.timestamp);163 },164});165```166167Cho cac schedule moi tenant - chang han, mot cron moi khach hang - ban tao chung dong qua management API.168169```typescript170import { schedules } from "@trigger.dev/sdk";171172await schedules.create({173 task: "daily-digest",174 cron: "0 9 * * *",175 timezone: "America/New_York",176 externalId: `customer_${customerId}`,177 deduplicationKey: `digest-${customerId}`,178});179```180181`deduplicationKey` lam cho cuoc goi idempotent: chay lai cung mot code khi deploy khong xep chong cac schedule trung lap.182183## Queues, Concurrency va Idempotency184185Ba primitive bao phu hau het nhu cau rate-limiting va sap xep.186187```mermaid188graph TB189 Trigger[trigger payload] --> IK{idempotencyKey<br/>thay?}190 IK -->|co| Reuse[Tra ve run hien co]191 IK -->|khong| CK[bucket concurrencyKey]192 CK --> Q[Queue voi<br/>concurrencyLimit]193 Q -->|slot co san| Run[Chay task]194 Q -->|slots day| Wait[Cho trong queue]195```196197Mot mau pho bien: mot queue moi tenant voi concurrency moi key nho de ton trong rate limit cua vendor, cong voi mot idempotency key de lam cho retry an toan.198199```typescript200await syncShopifyOrders.trigger(201 { shopId },202 {203 queue: { name: `shopify-${shopId}`, concurrencyLimit: 2 },204 concurrencyKey: shopId,205 idempotencyKey: `sync-${shopId}-${Date.now() / 60_000 | 0}`,206 }207);208```209210## Waits va Cong viec dai han211212Tasks co the tam dung ma khong giu ket noi hoac dot compute. Nen tang giu trang thai va tiep tuc ham khi wait hoan thanh.213214```typescript215import { wait } from "@trigger.dev/sdk";216217export const onboarding = task({218 id: "onboarding",219 run: async (payload: { userId: string }) => {220 await sendWelcomeEmail.triggerAndWait({ userId: payload.userId });221 await wait.for({ days: 1 });222 await sendTipsEmail.trigger({ userId: payload.userId });223 await wait.until({ date: oneWeekFromSignup(payload.userId) });224 await sendUpgradeOffer.trigger({ userId: payload.userId });225 },226});227```228229`triggerAndWait` la tinh nang sat thu: no trigger mot task con va treo parent cho den khi child hoan thanh. Ban soan tasks nhu cac ham async, nhung orchestration chay ben vung qua nhieu ngay hoac tuan.230231### Human-in-the-loop voi `wait.forToken`232233Cho luong phe duyet va AI gates, `wait.forToken` tam dung cho den khi ung dung cua ban callback voi mot ket qua.234235```typescript236import { task, wait } from "@trigger.dev/sdk";237238export const publishPost = task({239 id: "publish-post",240 run: async (payload: { draftId: string }) => {241 const draft = await generateAIContent(payload.draftId);242243 const token = await wait.createToken({ timeout: "7d" });244 await notifyEditor({ draftId: draft.id, token: token.id });245246 const decision = await wait.forToken<{ approved: boolean; notes?: string }>(247 token.id248 );249250 if (decision.approved) {251 return await publish(draft);252 }253 return await applyFeedback(draft, decision.notes);254 },255});256```257258Editor mo mot UI, xem xet ban nhap, nhap Phe duyet va backend cua ban hoan thanh token. Task tiep tuc tu noi no dung lai - ngay ca khi nhieu gio hoac ngay da troi qua.259260## Lifecycle Hooks261262Ban co the gan `init`, `onStart`, `onSuccess` va `onFailure` vao mot task hoac toan cuc trong `trigger.config.ts`. Su dung chung cho tracing, error reporting va setup chia se.263264```typescript265// trigger.config.ts266export default defineConfig({267 // ...268 init: async () => {269 Sentry.init({ dsn: process.env.SENTRY_DSN });270 },271 onFailure: async ({ error, ctx }) => {272 Sentry.captureException(error, {273 tags: { taskId: ctx.task.id, runId: ctx.run.id },274 });275 },276});277```278279`init` chay mot lan moi worker container khi boot, khong phai moi run, vi vay no la noi thich hop de thiet lap clients va pools.280281## Realtime trong Frontend282283Trigger.dev xuat ban thay doi trang thai run - status, metadata, output - qua mot streaming API. React hooks subscribe vao stream do va re-render tu dong.284285```typescript286// trigger/process-video.ts287import { task, metadata } from "@trigger.dev/sdk";288289export const processVideo = task({290 id: "process-video",291 run: async (payload: { videoId: string }) => {292 metadata.set("stage", "transcoding");293 await transcode(payload.videoId);294295 metadata.set("stage", "thumbnails");296 await generateThumbnails(payload.videoId);297298 metadata.set("stage", "uploading");299 const url = await uploadToCDN(payload.videoId);300301 return { url };302 },303});304```305306```tsx307// components/VideoStatus.tsx308"use client";309import { useRealtimeRun } from "@trigger.dev/react-hooks";310import type { processVideo } from "@/trigger/process-video";311312export function VideoStatus({313 runId,314 publicAccessToken,315}: {316 runId: string;317 publicAccessToken: string;318}) {319 const { run, error } = useRealtimeRun<typeof processVideo>(runId, {320 accessToken: publicAccessToken,321 });322323 if (error) return <p>Error: {error.message}</p>;324 if (!run) return <p>Loading...</p>;325326 return (327 <div>328 <p>Status: {run.status}</p>329 <p>Stage: {String(run.metadata?.stage ?? "queued")}</p>330 {run.output?.url && <video src={run.output.url} controls />}331 </div>332 );333}334```335336Ban tao public access token o phia server, voi pham vi cho mot run cu the, va gui den client. Hook xu ly auth, ket noi lai va cap nhat tang dan.337338Cho trigger-and-subscribe trong mot buoc:339340```tsx341import { useRealtimeTaskTrigger } from "@trigger.dev/react-hooks";342343const { submit, run, isLoading } = useRealtimeTaskTrigger<typeof processVideo>(344 "process-video",345 { accessToken: publicAccessToken }346);347348<button onClick={() => submit({ videoId })} disabled={isLoading}>349 Process video350</button>;351```352353## AI Agents va Streaming354355Trigger.dev da tro thanh mot runtime pho bien cho AI agents vi cac primitive giong nhau - thuc thi ben vung, retries, waits, metadata thoi gian thuc, human-in-the-loop - chinh xac la nhung gi agents can. Ban stream token tu mot model provider vao `metadata` trong khi run dien ra, frontend render chung truc tiep va run song sot qua tool calls dai han ma khong dot timeout serverless.356357```typescript358import { task, metadata } from "@trigger.dev/sdk";359import { streamText } from "ai";360import { anthropic } from "@ai-sdk/anthropic";361362export const researchAgent = task({363 id: "research-agent",364 maxDuration: 1800,365 run: async (payload: { question: string }) => {366 const result = streamText({367 model: anthropic("claude-opus-4-7"),368 system: "You are a research assistant. Use the web.",369 prompt: payload.question,370 tools: { webSearch },371 });372373 let fullText = "";374 for await (const chunk of result.textStream) {375 fullText += chunk;376 metadata.set("partial", fullText);377 }378379 return { answer: fullText, usage: await result.usage };380 },381});382```383384Frontend su dung `useRealtimeRun` va doc `run.metadata.partial` de render phan hoi streaming, theo cung mot cach ban se render mot chat completion - tru rang cai nay song sot qua mot reload trang day du.385386## Deploying387388Deploys bien dich tasks cua ban thanh mot bundle co phien ban, xay dung mot container va swap traffic mot cach atomic. Cac runs cu dang chay tiep tuc su dung phien ban truoc.389390```bash391npx trigger.dev@latest deploy --env prod392```393394Trong CI ban thuong noi day no vao cung mot workflow chuyen ung dung cua ban:395396```yaml397# .github/workflows/deploy.yml398- name: Deploy Trigger.dev399 env:400 TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}401 run: npx trigger.dev@latest deploy --env prod402```403404Cho moi truong preview, truyen `--env preview --branch ${{ github.head_ref }}` va Trigger.dev tao mot moi truong co lap moi branch, phan anh cach Vercel xu ly preview deployment.405406## Self-Hosting vs Cloud407408Trigger.dev la ma nguon mo theo giay phep Apache 2.0. Ban co the self-host tren bat ky nen tang container nao (Docker Compose, Kubernetes, Fly.io) hoac su dung cloud quan ly tai trigger.dev.409410| Khia canh | Cloud | Self-hosted |411|--------|-------|-------------|412| **Setup** | Dang ky, chay `init` | Chay docker-compose hoac Helm chart |413| **Scaling** | Tu dong | Trach nhiem cua ban |414| **Pricing** | Moi run + moi compute | Chi chi phi infra |415| **Compliance** | SOC 2 | Bat ky gi moi truong cua ban cung cap |416| **Tot nhat cho** | Hau het cac doi | Cu tru du lieu nghiem ngat, infra tuy chinh |417418SDK va CLI giong nhau giua cac che do - ban thay doi mot co profile va tro den instance cua rieng ban.419420## Best Practices421422### 1. Giu payloads nho va co the serializable423424Truyen ID va tham chieu, khong phai doi tuong day du. Keo du lieu ben trong task. Dieu nay giu queue nho, payloads re de log va cho phep ban thay doi nguon du lieu ma khong can re-trigger.425426### 2. Idempotency keys tren moi cuoc goi ben ngoai427428Ket hop `idempotencyKey` tren task trigger voi idempotency keys tren API cua vendor (Stripe, OpenAI, vv). Retries se an toan tu dau den cuoi.429430### 3. Su dung `triggerAndWait` cho orchestration, khong phai `Promise.all` cua triggers431432Mot parent goi `triggerAndWait` ben vung soan thao tasks con. Mot parent trigger va resolve ngay lap tuc mat kha nang quan sat cua chuoi.433434### 4. Tag runs435436Them `tags` vao triggers (`tags: ["user:123", "feature:onboarding"]`) de ban co the loc dashboard va management API theo cac chieu kinh doanh.437438### 5. Giu `init` idempotent439440No chay tren moi cold start. Tranh migrations hoac side effect mot lan o do.441442## Ket luan443444Trigger.dev loai bo cac danh muc cong viec ma truoc day yeu cau xay dung mot he thong job tu dau. Ban viet TypeScript async, goi no tu bat ky dau va nen tang cung cap cho ban thuc thi ben vung, lap lich, queues, retries, cap nhat thoi gian thuc va cac mau human-in-the-loop ngay tu dau.445446Cung mot be mat chay mot cron ban dem la be mat chay mot AI agent nhieu buoc stream den frontend va tam dung de xem xet. Su hoi tu do la dieu khien framework dang xem xet nghiem tuc trong nam 2026, du ban co dang chay mot SaaS can cong viec nen dang tin cay hay van chuyen cac tinh nang AI song sot qua mot timeout serverless.447448> **Checklist Bat dau:**449>450> - [x] Dang ky tai trigger.dev hoac chay stack Docker self-hosted451> - [x] `npx trigger.dev@latest init` trong du an cua ban452> - [x] Dinh nghia task dau tien voi `task({ id, run })`453> - [x] Trigger no tu API va xem run trong dashboard454> - [x] Them `idempotencyKey` va `concurrencyKey` cho an toan production455> - [x] Noi day `useRealtimeRun` vao mot status component456> - [x] Deploy voi `trigger.dev deploy --env prod` tu CI457
:Trigger.dev: Cong viec nen ben vung va workflow AI trong TypeScriptlines 1-457 (END) — press q to close