# Što ćeš naučiti#
Next.js je odličan za request-response workloadove, ali pozadinski rad je mjesto gdje mnogi timovi gube vrijeme i pouzdanost. U 2026., pozadinski poslovi “production-grade” razine u Next.js-u najčešće kombiniraju tri građevna bloka: zakazane okidače, trajni (durable) red i workera koji može raditi dovoljno dugo da završi posao.
Ovaj vodič pokriva praktične obrasce za pozadinski rad na Vercelu i šire: Vercel Cron, ograničenja serverlessa, redove temeljene na Redisu i Upstashu te namjenske worker servise. Dobit ćeš i kriterije odlučivanja, arhitekturne dijagrame i checklistu spremnosti za produkciju koju možeš koristiti prije puštanja.
# Stvarnost u 2026.: serverless i Next.js nisu job runner#
Next.js pokreće API rute i Server Actions kao compute vezan uz zahtjev. To je važno jer su pozadinski poslovi često suprotnost: dugotrajni su, traže retryje i osjetljivi su na throughput.
Evo ograničenja oko kojih trebaš dizajnirati:
| Concern | Što se događa na serverlessu | Zašto je važno za poslove |
|---|---|---|
| Max execution time | Tvrdi timeout (ovisno o planu i platformi) | Dugi zadaci se prekidaju usred rada ako ih ne “chunk-aš” |
| Cold starts | Skokovita latencija | Cron i queue consumeri mogu krenuti sporo |
| Nema zajamčenog in-process statea | Instance su efemerne | In-memory redovi, lockovi i praćenje napretka će pucati |
| Skaliranje konkurentnosti | Auto-skalira s prometom | Super za burstove, ali može preopteretiti downstream sustave |
| Background threadovi | Nisu pouzdani | Ne bi trebao pokretati posao nakon slanja odgovora |
Ako si na Vercelu, pretpostavi da se funkcija može zaustaviti u bilo kojem trenutku i dizajniraj za idempotentnost i nastavak (resume). Ako dodatno podešavaš caching i rendering, uskladi pozadinski rad sa strategijom svježine podataka. Puno timova zaboravi tu poveznicu i završi sa zastarjelim stranicama ili nepotrebnim recomputeom. Za dublju perspektivu cachea, vidi Next.js strategije cacheiranja za SSR, ISR i SWR.
# Odabir pravog obrasca: matrica odlučivanja#
Koristi ovu matricu za brz odabir pristupa. Većina produkcijskih sustava na kraju koristi barem dva obrasca: cron plus red, i red plus workere.
| Use case | Preporučeni obrazac | Tipični alati | Napomene |
|---|---|---|---|
| Osvježavanje analitike jednom na sat | Cron okida enqueue poslova | Vercel Cron plus Upstash Redis | Izbjegavaj odraditi posao unutar cron funkcije |
| Slanje transakcijskih emailova | Red s retryjima | Upstash Redis, BullMQ na Redisu | Osiguraj idempotentnost kako bi izbjegao duplikate |
| Generiranje PDF-ova ili videa | Namjenski worker servis | Containeri na Fly.io, Render, AWS ili self-hosted | Napredak u DB-u, streamanje logova |
| Sinkronizacija podataka iz third-party API-ja | Cron plus red plus rate limiting | Vercel Cron, Redis, worker | Rate limit i backoff su ključni |
| Export pokrenut od korisnika | Enqueue na zahtjev, polling statusa | Redis red, worker, DB | Tablica statusa posla i potpisani URL-ovi za download |
| Fan-out webookova | Red, batch obrada | QStash, Redis Streams | Spriječi da jedan webhook blokira API |
🎯 Ključna poruka: Ako zadatak može premašiti serverless time limit ili treba snažnu semantiku retryja, stavi ga u red i pokreni u workeru. Ne pokušavaj “samo ga odraditi u API ruti”.
# Obrazac 1: Cron na Vercelu — kako to napraviti ispravno#
Vercel Cron je scheduler koji pogađa URL na tvojem deploymentu prema rasporedu. Odličan je za okidanje posla, ali nije punokrvni scheduler koji jamči single execution u svim failure modeovima osim ako dodaš vlastite zaštite.
Arhitektura: Cron okidač plus red#
+-------------+ +-------------------+ +------------------+
| Vercel Cron | HTTP | Next.js API Route | enqueue| Queue (Redis) |
| (schedule) +-------->+ /api/cron/* +-------->+ Upstash / Redis |
+-------------+ +-------------------+ +---------+--------+
|
| consume
v
+--------+--------+
| Worker Service |
| (long running) |
+-----------------+Ova arhitektura razdvaja zakazivanje od izvršavanja. Tvoja cron ruta treba raditi što manje: validirati auth, uzeti lock, enqueueati poslove i vratiti odgovor.
Minimalna Vercel Cron konfiguracija#
U Vercelu cron poslove definiraš u vercel.json. Drži rasporede jednostavnima i dovoljno učestalima da se sustav oporavi od grešaka.
{
"crons": [
{ "path": "/api/cron/sync-products", "schedule": "0 * * * *" },
{ "path": "/api/cron/cleanup", "schedule": "15 2 * * *" }
]
}Zaštiti endpoint i izbjegni duplo izvođenje#
Cron endpointi moraju biti zaštićeni. Koristi tajni header, provjeri token i dodaj distribuirani lock kako bi samo jedna egzekucija u jednom trenutku enqueueala posao.
// app/api/cron/sync-products/route.ts
import { NextResponse } from "next/server";
import { Redis } from "@upstash/redis";
export const runtime = "nodejs";
const redis = Redis.fromEnv();
export async function GET(req: Request) {
const auth = req.headers.get("authorization");
if (auth !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: "unauthorized" }, { status: 401 });
}
const lockKey = "lock:cron:sync-products";
const lock = await redis.set(lockKey, "1", { nx: true, ex: 55 });
if (!lock) return NextResponse.json({ ok: true, skipped: "locked" });
// enqueue lightweight units of work
await redis.lpush("q:product-sync", JSON.stringify({ type: "sync", at: Date.now() }));
return NextResponse.json({ ok: true });
}Ovo koristi Redis lock s istekom kraćim od intervala rasporeda. Ako cron padne, lock se sam oslobodi.
⚠️ Upozorenje: Ne zovi third-party API-je direktno unutar cron funkcije ako može trajati dulje od par sekundi ili mora paginirati kroz puno rezultata. Udarit ćeš u timeoutove, a djelomični napredak bit će teško oporaviti.
# Obrazac 2: Redovi u Next.js-u s Upstashom i Redisom#
Redovi ti daju trajnost, retryje i buffer kada promet naglo skoči. Također ti omogućuju da postaviš konkurentnost koja odgovara ograničenjima tvojih downstream sustava.
U 2026. čest setup na Vercelu je:
- Next.js API rute i Server Actions enqueueaju poslove.
- Upstash Redis sprema red.
- Worker konzumira poslove na platformi koja podržava dugotrajne procese.
Model podataka za Redis red#
Neka poruka u redu bude minimalna. Velike payloadove drži u object storageu ili bazi, a u poruci proslijedi reference.
| Field | Primjer | Zašto |
|---|---|---|
jobId | job_01HZY... | Korelacija i deduplikacija |
type | send_email | Rutiranje i handleri |
payloadRef | db:export:123 | Izbjegavanje velikih poruka |
attempt | 0 | Upravljanje retryjima |
createdAt | 1714600000000 | Debugging i SLA-ovi |
Enqueue iz Server Action ili API rute#
Koristi idempotency key za akcije koje pokreće korisnik. Praktičan pristup je spremiti idempotency key u Redis s TTL-om i preskočiti duplikate.
// app/actions/requestExport.ts
"use server";
import { Redis } from "@upstash/redis";
import { nanoid } from "nanoid";
const redis = Redis.fromEnv();
export async function requestExport(userId: string, idempotencyKey: string) {
const dedupeKey = `dedupe:export:${userId}:${idempotencyKey}`;
const ok = await redis.set(dedupeKey, "1", { nx: true, ex: 3600 });
if (!ok) return { status: "duplicate" as const };
const jobId = `job_${nanoid()}`;
await redis.lpush(
"q:exports",
JSON.stringify({ jobId, type: "export_csv", userId, attempt: 0, createdAt: Date.now() })
);
return { status: "queued" as const, jobId };
}Ovo sprječava da slučajni double-click napravi više exportova.
Konzumiranje poslova: worker petlja s visibility timeoutom#
Naivan RPOP može izgubiti poslove ako se worker sruši usred obrade. Preferiraj pouzdan obrazac poput BRPOPLPUSH ili Redis Streams. Ako želiš jednostavnost, implementiraj processing listu plus “reaper”.
// worker/consumeExports.ts
import { Redis } from "@upstash/redis";
const redis = Redis.fromEnv();
async function main() {
while (true) {
const job = await redis.brpoplpush("q:exports", "q:exports:processing", 10);
if (!job) continue;
try {
const msg = JSON.parse(job);
// do work...
await redis.lrem("q:exports:processing", 1, job);
} catch (e) {
// keep in processing for a reaper to retry, or move to DLQ
console.error("job_failed", { error: String(e) });
}
}
}
main().catch((e) => {
console.error(e);
process.exit(1);
});Zatim dodaš periodični reaper job koji provjerava q:exports:processing i vraća u red zastarjele stavke na temelju timestampova spremljenih u zasebnom hashu. Ako ne želiš održavati ovu semantiku, razmisli o queue biblioteci višeg nivoa ili Redis Streams consumer grupama.
💡 Savjet: Kreni s jednim redom po domeni workloada, ne jednim redom po tipu posla. Primjer:
q:emails,q:exports,q:sync. Ovo drži operacije pod kontrolom i omogućuje postavljanje konkurentnosti po domeni.
# Obrazac 3: Managed HTTP redovi za “serverless first” timove#
Ako tvoj tim želi izbjeći pokretanje persistent workera, managed HTTP-based isporuka može biti dobar kompromis. Tipični tok je:
- Tvoja aplikacija objavi poruku na endpoint reda.
- Queue servis retryja isporuku na handler URL dok ne uspije.
- Tvoj handler mora biti idempotentan jer može primiti duplikate.
Ovo radi dobro za zadatke koji se mogu završiti unutar serverless time limitova, ali i dalje trebaju retryje i buffering, poput fan-out webookova, slanja emailova ili kratkih transformacija podataka.
Arhitektura: HTTP isporuka iz reda#
+------------------+ publish +--------------------+
| Next.js (Vercel) |------------------------>+ Managed HTTP Queue |
| API / Actions | | retries + backoff |
+--------+---------+ +---------+----------+
^ |
| | deliver HTTP
| v
| +--------+---------+
| | Next.js Handler |
| | /api/jobs/* |
| +------------------+Tradeoff je jednostavan: lakše operacije, manje kontrole nad throughputom i konkurentnošću u odnosu na namjenski worker na Redisu.
# Obrazac 4: Dugotrajni zadaci s namjenskim workerima#
Sve što je CPU-heavy ili time-heavy ne bi smjelo ići na serverless. Česti primjeri:
- Generiranje PDF-a s headless Chromiumom
- Transkodiranje videa
- Veliki data exportovi
- Višekoračni ETL pipelineovi
Gdje pokretati workere u 2026.#
Odaberi platformu za workere koja odgovara tvojoj operativnoj zrelosti i compliance potrebama.
| Platform | Najbolje za | Prednosti | Nedostaci |
|---|---|---|---|
| Fly.io ili Render | Mali do srednji timovi | Jednostavan deploy, dobar DX | Regionalno podešavanje i scaling odluke |
| AWS ECS ili Kubernetes | Veće organizacije | Potpuna kontrola, visok scale | Više ops overhead-a |
| VM sa systemd | Osjetljivo na trošak | Najjeftiniji predvidivi compute | Ručno skaliranje i monitoring |
| n8n (automatizacija) | Business workflowovi | Brza iteracija, puno konektora | Nije idealno za CPU-heavy workloadove |
Ako je tvoj workload uglavnom integracije i odobravanja, razmisli o prebacivanju dijelova u automatizaciju. Često kombiniramo Next.js za product UI i n8n za back-office workflowove poput CRM sinkronizacije, generiranja računa i rutiranja upozorenja. Vidi Samioda automation.
Praćenje statusa posla u bazi#
Uvijek trajno spremaj stanje posla izvan workera kako bi UI mogao prikazati napredak i kako bi se moglo nastaviti nakon restarta.
| State | Značenje | Spremljena polja |
|---|---|---|
queued | prihvaćeno, čeka | jobId, type, createdAt |
running | obrada krenula | startedAt, workerId |
succeeded | završeno | finishedAt, resultRef |
failed | premašeni retryji ili fatalno | finishedAt, errorCode, errorMessage |
Tok user exporta postaje:
- 1UI zatraži export, server enqueuea posao i upiše
queued. - 2Worker postavi
running, odradi obradu, spremi datoteku u object storage. - 3Worker postavi
succeededs referencom na potpisani download URL. - 4UI poll-a status posla ili koristi WebSocket evente ako ih imaš.
# Praktičan end-to-end primjer: sinkronizacija proizvoda uz rate limit#
Pretpostavimo da moraš sinkronizirati 200.000 proizvoda iz third-party API-ja s rate limitom 60 zahtjeva u minuti. Ako to pokušaš u jednom cron pozivu, failat će, a ako to radiš na svaki request, preopteretit ćeš API.
Robustan pristup:
- Vercel Cron se pokreće svaki sat.
- Cron enqueuea page poslove za workera.
- Worker obrađuje stranice s konkurentnošću 1 do 3, poštujući limite.
- Worker zapisuje napredak u DB, kako bi se moglo nastaviti.
Primjer: Cron enqueuea page poslove#
// app/api/cron/enqueue-product-pages/route.ts
import { NextResponse } from "next/server";
import { Redis } from "@upstash/redis";
export const runtime = "nodejs";
const redis = Redis.fromEnv();
export async function GET(req: Request) {
if (req.headers.get("authorization") !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: "unauthorized" }, { status: 401 });
}
// Example: 100 pages, keep messages small
for (let page = 1; page <= 100; page++) {
await redis.lpush("q:sync-products", JSON.stringify({ type: "sync_page", page, attempt: 0 }));
}
return NextResponse.json({ ok: true, enqueued: 100 });
}Worker primjenjuje backoff i retryje#
Neka retry logika bude deterministička. Koristi eksponencijalni backoff poput delayMs = min(60000, 1000 * 2^attempt) i prebaci u dead-letter queue nakon N pokušaja.
// worker/syncProducts.ts
import { Redis } from "@upstash/redis";
const redis = Redis.fromEnv();
function backoffMs(attempt: number) {
return Math.min(60000, 1000 * Math.pow(2, attempt));
}
async function sleep(ms: number) {
await new Promise((r) => setTimeout(r, ms));
}
async function main() {
while (true) {
const raw = await redis.brpoplpush("q:sync-products", "q:sync-products:processing", 10);
if (!raw) continue;
const msg = JSON.parse(raw) as { page: number; attempt: number };
try {
// Call third-party API, write to DB, etc.
// Respect rate limit with small delays per page
await sleep(1200);
await redis.lrem("q:sync-products:processing", 1, raw);
} catch (e) {
const attempt = msg.attempt + 1;
await redis.lrem("q:sync-products:processing", 1, raw);
if (attempt >= 5) {
await redis.lpush("q:sync-products:dlq", JSON.stringify({ ...msg, attempt, error: String(e) }));
} else {
await sleep(backoffMs(attempt));
await redis.lpush("q:sync-products", JSON.stringify({ ...msg, attempt }));
}
}
}
}
main().catch((e) => {
console.error(e);
process.exit(1);
});Ovo je namjerno jednostavno, ali pokazuje ključnu mehaniku: visibility listu, retryje, backoff i DLQ.
# Observability: razlika između poslova koji rade i poslova kojima možeš upravljati#
Pozadinski poslovi failaju drugačije od web zahtjeva. Bez observabilityja, greške ćeš najčešće primijetiti tek kad se kupac požali.
Instrumentiraj tri sloja:
- 1Sloj okidanja: cron pozivi i enqueue zahtjevi.
- 2Sloj reda: lag, throughput i DLQ veličina.
- 3Sloj workera: trajanje, stopa grešaka i latencija vanjskih ovisnosti.
Minimalno, logiraj:
jobIdtypeattemptcorrelationIdza izvorni request- start i end timestampove
Zatim dodaj metrike:
- percentile trajanja posla, posebno p95 i p99
- stopa failova po tipu posla
- dubina reda i time-in-queue
- broj retryja i rast DLQ-a
Ako ti treba strukturiran pristup, koristi našu checklistu i obrasce za observability u Observability web aplikacija: logging, metrike, tracing.
ℹ️ Napomena: U serverless okruženjima logovi mogu biti fragmentirani kroz invokacije. Trajno spremaj prijelaze stanja posla u tablicu u bazi kako bi mogao rekonstruirati što se dogodilo čak i ako se logovi samplaju ili rotiraju.
# Checklista spremnosti za produkciju#
Koristi ovu checklistu prije nego što se osloniš na pozadinske poslove za kritične workflowove poput naplate, notifikacija ili sinkronizacije podataka.
Sigurnost i ispravnost#
- Idempotency key-evi za akcije pokrenute od korisnika i webhook handlere.
- Strategija deduplikacije za cron i retryje.
- Distribuirani lock za cron okidače i sve “singleton” poslove.
- Pretpostavi at-least-once isporuku, uz siguran ponovni processing.
- Jasna DLQ politika i operator runbook za replay.
Pouzdanost i skaliranje#
- Ograničenja konkurentnosti po redu kako bi se poštovali downstream rate limitovi.
- Backoff strategija: eksponencijalna s jitterom ako imaš puno workera.
- Timeoutovi na svim outbound zahtjevima, nikad beskonačno.
- Strategija chunkanja za velike poslove, uz resumable napredak.
- Odvojeni redovi za različite workloadove kako bi se izolirali kvarovi.
Sigurnost i usklađenost (compliance)#
- Cron i job endpointi zahtijevaju tajni token ili verifikaciju potpisa.
- Least-privilege tajne za workere, odvojene od web aplikacije kad je moguće.
- Osjetljivi payloadovi u DB-u ili object storageu, ne u porukama reda.
- Audit log za kritične poslove poput isplata ili promjena pretplate.
Operacije i observability#
- Dashboard za dubinu reda, stopu uspješnosti i DLQ veličinu.
- Pragovi za alerte vezani uz SLA-ove, ne šum.
- Correlation id prenesen od web requesta do posla i workera.
- Status posla trajno spremljen u DB, uključujući razloge faila i timestampove.
Deploy i rollback#
- Worker i aplikacija se mogu deployati neovisno.
- Verzije sheme poruke posla, tako da stariji workeri mogu ignorirati nova polja.
- Backward-compatible handleri tijekom roll-outa.
- Feature flagovi za nove tipove poslova.
# Ključne poruke#
- Koristi Vercel Cron kao okidač, ne kao engine za izvršavanje: validiraj auth, uzmi lock, enqueueaj posao, brzo vrati odgovor.
- Pretpostavi da se serverless invokacije mogu završiti ranije i da se mogu izvršiti više puta; dizajniraj poslove da budu idempotentni i resumable.
- Za pouzdanu obradu u pozadini kombiniraj trajni red s workerom koji podržava dugotrajni compute i kontroliranu konkurentnost.
- Poruke u redu drži malima, a velike payloadove referenciraj iz baze ili object storagea kako bi smanjio greške i troškove.
- Učini poslove operabilnima: spremaj stanja posla, prati lag reda i rast DLQ-a te dodaj alerte vezane uz stvarni utjecaj.
# Zaključak#
Next.js u 2026. može podržati ozbiljnu obradu u pozadini, ali samo ako prestaneš tretirati API rute kao job runner. Pouzdan put je konzistentan: cron okidači enqueueaju, redovi bufferaju i retryjaju, a workeri obrađuju uz jasna ograničenja i observability.
Ako želiš pomoć oko dizajna queue-and-worker arhitekture za Vercel, odabira između Upstasha i managed isporuke ili spajanja end-to-end observabilityja, Samioda to može implementirati s Reactom i Next.js-om, uz automatizaciju gdje ima smisla. Kreni ovdje: Samioda automatizacija, i usporedo pregledaj svoju strategiju cacheiranja uz svježinu jobova u Next.js strategije cacheiranja.
FAQ
Više iz kategorije Web razvoj
Sve →Next.js i18n s App Routerom: lokalizirano rutiranje, SEO i workflowi za sadržaj (vodič za 2026.)
Implementirajte Next.js i18n u App Routeru s lokaliziranim rutiranjem, detekcijom jezika, SEO-sigurnim metapodacima i skalabilnim workflowima prevođenja za JSON, CMS ili lokalizacijske platforme.
React obrasci u velikim aplikacijama: React Hook Form + Zod obrasci za složene proizvode
Najbolje prakse za React obrasce u velikim aplikacijama uz React Hook Form i Zod: validacija po shemi, višekratno upotrebljiva polja, asinkrone provjere, višekoračni tokovi, performanse, pristupačnost i obrasci integracije sa serverom/API-jem.
Implementacija Stripe pretplata u Next.js-u: Billing Portal, webhookovi i prava pristupa
Vodič spreman za produkciju za Next.js Stripe pretplate: planovi i probni periodi, Billing Portal, provjera webhookova, idempotentna obrada, mapiranje prava pristupa i testiranje sa Stripe CLI-jem.
Trebate pomoć s projektom?
Gradimo prilagođena rješenja koristeći tehnologije iz ovog članka. Senior tim, fiksne cijene.
Povezani članci
Next.js multitenant SaaS arhitektura: modeli tenancije, rutiranje, autentikacija i izolacija podataka (Vodič za 2026.)
Praktičan vodič za Next.js multitenant SaaS arhitekturu: modeli tenancije, tenant-aware rutiranje uz App Router i middleware, obrasci autentikacije te učvršćivanje izolacije podataka kako bi se spriječila curenja.
Observabilnost web aplikacija: praktični vodič za logove, metrike i tracing za React i Next.js
End-to-end, produkcijski spremna observability postava za React i Next.js: praćenje grešaka, nadzor performansi, strukturirani logovi, tracing, nadzorne ploče i alerti koji hvataju stvarne probleme.
Arhitektura React komponenti za skaliranje: obrasci za održiv dizajnerski sustav
Pragmatična arhitektura React komponenti za velike React i Next.js codebaseove: kompozicija, složene (compound) i polimorfne komponente, tematiziranje, konvencije mapa, anti-uzorci i plan refaktoriranja koji vaš tim može pratiti.