spinny:~/writing $ vim trigger-dev-background-jobs-guide.md
1~2A legtobb gyartasi alkalmazasnak olyan munkara van szuksege, ami nem fer bele a request/response ciklusba: emailek kuldese, feltoltesek feldolgozasa, AI pipeline-ok futtatasa, harmadik felek adatainak szinkronizalasa, jelentesek generalasa. A hagyomanyos valasz egy queue (Redis, SQS, RabbitMQ), egy worker flotta, egy utemezo es egy torekeny ragsasztos kod halom, ami minden deploy-nal eltorik.3~4A [Trigger.dev](https://trigger.dev) ezt a stack-et egyetlen TypeScript SDK-ba sukiti. Funkciokat irsz, barhonnan hivod oket, es a platform kezeli a queueing-et, retries-et, observability-t, schedulinget es a tartos vegrehajtast. A taskok addig futnak, ameddig csak kell - nincs 10 masodperces serverless timeout, nincs elveszett munka redeploy-nal.5~6## Miert Trigger.dev7~8A 2026-os valtas a tartos vegrehajtas. A workflow-knak tul kell elniuk az ujraindításokat, osszeomlasokat, deploy-okat es rate limit-eket. Valos idoben kell streamelniuk az elorehaladast a UI-ra, es szunetelniuk kell az emberi inputra. A Trigger.dev a 3-as verzioban ezekre a kovetelmenyekre lett ujjaepitve, es folyamatosan bovíti AI infrastrukturalis felulet.9~10```mermaid11graph LR12 App[Az alkalmazasod] -->|trigger| API[Trigger.dev API]13 API --> Queue[Tartos Queue]14 Queue --> Worker[Worker Container]15 Worker -->|run task| Task[A te Task kodod]16 Task -->|metadata| Realtime[Realtime Stream]17 Realtime --> UI[React UI]18 Worker --> Storage[Run State Store]19```20~21A modell egyszeru: taskokat exportkent definialsz, a SDK felveszi oket, a platform utemezi es izolalt konteneerekben futtatja oket, es a run allapot megorzodik, hogy folytathasd, ujraprobalhasd es megfigyelhesd.22~23## Kezdes24~25### Inicializaltassuk projektet26~27```bash28npx trigger.dev@latest login29npx trigger.dev@latest init30```31~32Ez letrehoz egy `trigger.config.ts` fajlt es egy `trigger/` konyvtarat pelda taskokkal. A config fajl a projekt igazsag forrasa: melyik konyvtarak tartalmaznak taskokat, build beallitasokat, lifecycle hookokat es runtime opciokat.33~34```typescript35// trigger.config.ts36import { defineConfig } from "@trigger.dev/sdk";37~38export 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```55~56### Futtass taskokat helyileg57~58```bash59npx trigger.dev@latest dev60```61~62A dev szerver csatlakozik a felhohoz, regisztralja a taskjaidat es streameli a runokat a helyi kododon keresztul. Tortest pontokat allitasz be a szerkesztodben, es valodi triggerekre talalsz - ugyanaz a ciklus, amit barmilyen normalis Node.js projektben hasznalnal.63~64## Egy Task definialasa65~66A task egy exportalt objektum egyedi `id`-val es egy `run` funkcioval. A SDK megvizsgalja az exporokat a `dirs`-en at, es automatikusan regisztralja oket.67~68```typescript69// trigger/send-welcome-email.ts70import { task } from "@trigger.dev/sdk";71import { Resend } from "resend";72~73const resend = new Resend(process.env.RESEND_API_KEY);74~75export 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 });90~91 if (error) throw error;92 return { messageId: data?.id };93 },94});95```96~97Harom dolog, amire figyelni kell:98~991. **Nincs timeout a run torzsben.** A platform a `maxDuration` configon keresztul kezeli a vegrehajtasi idot, nem a runtime-on.1002. **A throws-ok retries-ek.** A SDK elkapja a kiveteleket es ujrafuttat exponencialis backoff-fal a `retry` policy szerint.1013. **A visszateresi ertek megorzodik.** Mas taskok es a frontended barhonnan olvashatja a `run.output`-ot.102~103## Taskok triggerelese104~105Egy taskot hivsz a backendrol, az API route-jaibol vagy egy masik taskbol.106~107```typescript108import { sendWelcomeEmail } from "@/trigger/send-welcome-email";109~110const 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);120~121console.log(handle.id); // run_xyz - hasznald a kovetesere vagy a halados megjelenitesere122```123~124Az opciok sok viselkedest oldanak fel egy hivasban:125~126- **`idempotencyKey`** - ha mar letezik egy run ugyanazzal a kulccsal, a SDK a meglevo handle-t adja vissza ahelyett, hogy duplazna a munkat.127- **`concurrencyKey`** - serializalja a kulcsot megosztó runokat, hogy ne lepd tul a per-tenant rate limit-et.128- **`queue.concurrencyLimit`** - globalis cap a queue-hoz minden kulcson at.129- **`delay`** - a runot egy jovobeni idore utemezi.130- **`ttl`** - ha a run addigra nem indult el, automatikusan lejar.131~132### Batch trigger133~134Fan-out workloadokhoz a `batchTrigger` legfeljebb 500 elemet fogad el hivasonkent es egy runot keszit elemenkent.135~136```typescript137await sendWelcomeEmail.batchTrigger(138 newUsers.map((u) => ({139 payload: { email: u.email, name: u.name },140 options: { idempotencyKey: `welcome-${u.id}` },141 }))142);143```144~145## Utemezett Taskok146~147A cron job-ok elsoosztalyu deklaraciokka valnak. Maga a schedule egy kulonallo objektum, amit tobbszor csatolhatsz egy taskhoz.148~149```typescript150// trigger/daily-digest.ts151import { schedules } from "@trigger.dev/sdk";152~153export 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);161~162 await sendDigestForDate(payload.timestamp);163 },164});165```166~167Per-tenant schedule-ekhez - mondjuk egy cron ugyfelenkent - dinamikusan letrehozod oket a management API-n keresztul.168~169```typescript170import { schedules } from "@trigger.dev/sdk";171~172await 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```180~181A `deduplicationKey` idempotensse teszi a hivast: ugyanazon kod ujrafuttatasa deploy-kor nem stackeli a duplikalt schedule-eket.182~183## Queues, Konkurencia es Idempotencia184~185Harom primitiv lefedi a rate-limiting es rendezesi igenyek nagy reszet.186~187```mermaid188graph TB189 Trigger[trigger payload] --> IK{idempotencyKey<br/>latott?}190 IK -->|igen| Reuse[Visszater letezo run]191 IK -->|nem| CK[concurrencyKey bucket]192 CK --> Q[Queue<br/>concurrencyLimit-tel]193 Q -->|slot elerheto| Run[Task futtatasa]194 Q -->|slotok teli| Wait[Varakozas a queueban]195```196~197Egy gyakori minta: egy queue tenantonkent kis per-key konkurenciaval a vendor rate limit tiszteletben tartasahoz, plusz egy idempotencia kulcs a retries biztossagahoz.198~199```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```209~210## Varakozas es hosszan futo munka211~212A taskok megallhatnak anelkul, hogy tartanak egy kapcsolatot vagy egetnenek compute-ot. A platform megorzi az allapotot es folytatja a funkciot, amikor a varakozas befejezodik.213~214```typescript215import { wait } from "@trigger.dev/sdk";216~217export 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```228~229A `triggerAndWait` a killer feature: kivaltja a gyermek taskot es felfuggeszti a szuolot, amig a gyermek befejezodik. A taskokat async funkciokent komponalod, de az orchestralas tartoasan fut napokon vagy heteken at.230~231### Human-in-the-loop a `wait.forToken`-nel232~233Approval folyamatokhoz es AI gate-ekhez a `wait.forToken` szunetel, amig az alkalmazasod vissza nem hív egy eredmennyel.234~235```typescript236import { task, wait } from "@trigger.dev/sdk";237~238export const publishPost = task({239 id: "publish-post",240 run: async (payload: { draftId: string }) => {241 const draft = await generateAIContent(payload.draftId);242~243 const token = await wait.createToken({ timeout: "7d" });244 await notifyEditor({ draftId: draft.id, token: token.id });245~246 const decision = await wait.forToken<{ approved: boolean; notes?: string }>(247 token.id248 );249~250 if (decision.approved) {251 return await publish(draft);252 }253 return await applyFeedback(draft, decision.notes);254 },255});256```257~258A szerkeszto megnyit egy UI-t, atnezi a piszkozatot, ratallintat a Jovahagyas-ra es a backended befejezi a tokent. A task onnan folytatodik, ahol abbahagyta - meg akkor is, ha orak vagy napok teltek el.259~260## Lifecycle Hookok261~262Csatolhatsz `init`, `onStart`, `onSuccess` es `onFailure`-t egy taskhoz vagy globalisan a `trigger.config.ts`-ben. Hasznald oket tracinghez, error reportinghez es megosztott setuphoz.263~264```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```278~279Az `init` egyszer fut worker containerenkent boot-kor, nem runonkent, ezert ez a megfelelo hely a kliensek es poolok beallitasara.280~281## Realtime a frontenden282~283A Trigger.dev publikalja a run allapot valtozasait - status, metadata, output - egy streaming API-n keresztul. A React hookok feliratkoznak erre a streamre es automatikusan ujrarenderelnek.284~285```typescript286// trigger/process-video.ts287import { task, metadata } from "@trigger.dev/sdk";288~289export const processVideo = task({290 id: "process-video",291 run: async (payload: { videoId: string }) => {292 metadata.set("stage", "transcoding");293 await transcode(payload.videoId);294~295 metadata.set("stage", "thumbnails");296 await generateThumbnails(payload.videoId);297~298 metadata.set("stage", "uploading");299 const url = await uploadToCDN(payload.videoId);300~301 return { url };302 },303});304```305~306```tsx307// components/VideoStatus.tsx308"use client";309import { useRealtimeRun } from "@trigger.dev/react-hooks";310import type { processVideo } from "@/trigger/process-video";311~312export 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 });322~323 if (error) return <p>Error: {error.message}</p>;324 if (!run) return <p>Loading...</p>;325~326 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```335~336Generalod a public access tokent a szerver oldalan, egy specifikus runra scoped, es elkuldod a kliensnek. A hook kezeli az autht, az ujra csatlakozast es az inkrementalis frissiteseket.337~338Trigger-and-subscribe-hoz egy lepesben:339~340```tsx341import { useRealtimeTaskTrigger } from "@trigger.dev/react-hooks";342~343const { submit, run, isLoading } = useRealtimeTaskTrigger<typeof processVideo>(344 "process-video",345 { accessToken: publicAccessToken }346);347~348<button onClick={() => submit({ videoId })} disabled={isLoading}>349 Process video350</button>;351```352~353## AI Agentek es Streaming354~355A Trigger.dev nepszeru runtime-ma valt az AI agentek szamara, mert ugyanazok a primitivek - tartos vegrehajtas, retries, varakozasok, valos ideju metadata, human-in-the-loop - pontosan azok, amikre az agenseknek szuksegunk van. Tokeneket streamelsz egy modell szolgaltatotol a `metadata`-ba, mialatt a run zajlik, a frontend elve renderelje oket, es a run tuleli a hosszan futo tool callokat anelkul, hogy egetne egy serverless timeoutot.356~357```typescript358import { task, metadata } from "@trigger.dev/sdk";359import { streamText } from "ai";360import { anthropic } from "@ai-sdk/anthropic";361~362export 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 });372~373 let fullText = "";374 for await (const chunk of result.textStream) {375 fullText += chunk;376 metadata.set("partial", fullText);377 }378~379 return { answer: fullText, usage: await result.usage };380 },381});382```383~384A frontend a `useRealtimeRun`-ot hasznalja es olvassa a `run.metadata.partial`-t a streaming valasz renderelesere, ugyanugy, mintha egy chat completiont rendererel - kiveve, hogy ez tuleli egy teljes oldal ujratoltest.385~386## Deployment387~388A deployok lefordijak a taskjaidat egy verziozott bundle-be, kepetnek egy konteneert es atomikusan atvaltjak a forgalmat. A regi in-flight runok tovabbra is hasznaljak az elozo verziot.389~390```bash391npx trigger.dev@latest deploy --env prod392```393~394CI-ben tipikusan ezt ahhoz a workflow-hoz csatolod, amelyik a kuldi az alkalmazasod:395~396```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```403~404Preview kornyezetekhez add at a `--env preview --branch ${{ github.head_ref }}`-ot es a Trigger.dev letrehoz egy izolalt kornyezetet branchenkent, tukrozve azt, ahogy a Vercel kezeli a preview deploymenteket.405~406## Self-Hosting vs Cloud407~408A Trigger.dev nyilt forraskodu az Apache 2.0 licenc alatt. Self-hostolhatsz barmilyen container platformon (Docker Compose, Kubernetes, Fly.io) vagy hasznalhatod a managed cloudot a trigger.dev-en.409~410| Aspektus | Cloud | Self-hosted |411|--------|-------|-------------|412| **Setup** | Regisztracio, `init` futtatasa | docker-compose vagy Helm chart futtatasa |413| **Scaling** | Automatikus | A te felelosseged |414| **Pricing** | Per run + per compute | Csak infra koltseg |415| **Compliance** | SOC 2 | Amit a kornyezet biztosit |416| **Legjobb** | Legtobb csapatnak | Szigoru data residency, custom infra |417~418Az SDK es CLI azonosak a modok kozott - egy profile flag-et valtoztatsz es a sajat instance-edre mutatsz.419~420## Best Practices421~422### 1. Tartsd a payloadokat kicsiknek es szerializalhatonak423~424Add at az ID-kat es referenciakat, ne a teljes objektumokat. Hivd be az adatokat a tasken belul. Ez kicsiben tartja a queue-t, olcsova teszi a payloadok logolását es lehetove teszi, hogy az adat forrast valtoztasd anelkul, hogy ujra triggerelnel.425~426### 2. Idempotencia kulcsok minden kulso hivason427~428Kombinald az `idempotencyKey`-t a task triggeren a vendor API-k (Stripe, OpenAI, stb.) idempotencia kulcsaival. A retries end-to-end biztonsagosak lesznek.429~430### 3. Hasznald a `triggerAndWait`-et orchestraciohoz, nem a triggerek `Promise.all`-jat431~432Egy szuolo, amelyik `triggerAndWait`-et hiv, tartoasan komponalja a gyermek taskokat. Egy szuolo, amelyik triggerel es azonnal feloldoja, elveszti a lanc megfigyelhetoseget.433~434### 4. Tageld a runokat435~436Adj `tags`-eket a triggereknek (`tags: ["user:123", "feature:onboarding"]`), hogy szurhesd a dashboardot es a management API-t uzleti dimenziok szerint.437~438### 5. Tartsd az `init`-et idempotensnek439~440Minden cold startkor fut. Kerüld a migracikat vagy egyszeri side effecteket ott.441~442## Kovetkezte tes443~444A Trigger.dev eltunteti azokat a munka kategoriakat, amelyek korabban szukseges voltak ahhoz, hogy egy job rendszert epitsel a nullarol. Async TypeScriptet irsz, barhonnan hivod es a platform ad neked tartos vegrehajtast, schedulinget, queueket, retries-eket, valos ideju frissiteseket es human-in-the-loop mintakat dobozbol.445~446Ugyanaz a felulet, amelyik egy ejszakai cront hajt, az a felulet, amelyik egy multi-step AI agentet hajt, ami streamel a frontendre es szunetel a review-ert. Ez a konvergencia teszi a frameworkot 2026-ban komoly pillantasra meltova, akar egy SaaS-t mukodtetsz, amelyik megbizhato hatter munkat igenyel, akar AI funkciokat szallitasz, amelyek tulelik a serverless timeoutot.447~448> **Kezdes Checklist:**449>450> - [x] Regisztralj a trigger.dev-en vagy futtasd a self-hosted Docker stacket451> - [x] `npx trigger.dev@latest init` a projektben452> - [x] Definiald az elso taskodat a `task({ id, run })`-nel453> - [x] Triggereld az API-dbol es nezd a runot a dashboardon454> - [x] Adj hozza `idempotencyKey`-t es `concurrencyKey`-t a produkcios biztonsaghoz455> - [x] Csatold a `useRealtimeRun`-t egy status komponenshez456> - [x] Deployolj a `trigger.dev deploy --env prod`-dal CI-bol457~
NORMAL · trigger-dev-background-jobs-guide.md [readonly]457 lines · :q to close