import Fastify from 'fastify';
import { Queue, Worker } from 'bullmq';
const fastify = Fastify({ logger: true });
const pdfQueue = new Queue('pdf-generation', { connection: { host: 'localhost', port: 6379 } });
// Endpoint rapid care doar adaugă jobul în coadă
fastify.post('/generate-report', async (request, reply) => {
const { userId, reportData } = request.body as { userId: string, reportData: any };
await pdfQueue.add('generate', { userId, reportData });
return { status: 'queued', message: 'Raportul se procesează în background.' };
});
// Worker-ul rulează în același proces sau pe o mașină separată, fără limită de timp
const worker = new Worker('pdf-generation', async job => {
console.log(`Începe generarea PDF pentru userul ${job.data.userId}...`);
// Procesare grea (ex: Puppeteer, PDFKit)
await new Promise(resolve => setTimeout(resolve, 45000));
console.log('PDF generat cu succes!');
}, { connection: { host: 'localhost', port: 6379 } });
fastify.listen({ port: 3001 });Să fim sinceri: am început să folosim Next.js pentru absolut tot, chiar și acolo unde nu-și are locul. Next.js e genial pentru frontend și BFF (Backend-for-Frontend), dar când ai de făcut procesare grea, e o alegere proastă. Am trecut prin asta și vreau să îți arăt unde tragem linia și când e mai bine să ridici un server Node curat.
1. Problema cu serverless și timeout-urile
Atunci când rulezi Next.js pe platforme gen Vercel sau chiar self-hosted în Docker, rutele de API sunt gândite să se comporte ca niște funcții serverless. Am pățit asta la un proiect cu vreo 8.000 de utilizatori activi unde aveam un endpoint care genera rapoarte PDF masive. Generarea dura cam 40 de secunde.
Pe Vercel ne loveam constant de timeout-ul de 15 secunde pe planul Hobby sau chiar de cel de 30 de secunde pe planul Pro. Soluția n-a fost să facem upgrade la Enterprise, ci să mutăm logica pe un microserviciu separat, scris în Node.js simplu cu Fastify, rulat frumos într-un container Docker pe un VPS de 10 dolari. Am redus costurile cu 30% la build-uri și am scăpat definitiv de timeout-uri.
2. Job queue-urile și conexiunile persistente
Next.js nu este un job processor. Dacă vrei să rulezi BullMQ sau Bee-Queue pentru a trimite email-uri în background sau pentru a face web scraping, Next.js te va încurca teribil.
Într-un server Node clasic, poți configura o conexiune de Redis care să rămână deschisă pe tot parcursul vieții procesului. Ai control total pe event loop și poți face tuning pe garbage collection. În Next.js, la fiecare request de API se poate iniția o nouă conexiune la baza de date sau la Redis, riscând să atingi limita maximă de conexiuni (connection pool exhaustion) foarte rapid.
În plus, dacă rulezi serverul Next în mod serverless, nu poți avea un "Worker" care ascultă constant o coadă de mesaje. Ai nevoie de un proces de tip daemon, care rulează la infinit. Pentru asta, PM2 sau un container Docker cu un script Node simplu este sfânt.
3. Trade-off-ul sincer: Ce pierzi și ce câștigi?
Nu zice nimeni să arunci Next.js la gunoi. El își face treaba de minune pentru UI. Însă trebuie să înțelegi ce pierzi când separi backend-ul:
- Ce pierzi: Pierzi tipizarea end-to-end (cum e tRPC sau Server Actions unde ai tipurile din baza de date direct în componente). Trebuie să configurezi manual CORS, validarea de input (cu Zod sau Ajv) și să gestionezi două deployment-uri separate în loc de unul singur.
- Ce câștigi: Performanță brută. Un server Fastify pornește în sub o secundă, consumă 30MB de RAM în standby (spre deosebire de Next.js care sare de 150MB) și poate duce mii de request-uri pe secundă fără să transpire.
Eu folosesc regula asta simplă: dacă endpoint-ul doar ia niște date din DB și le trimite la client, îl las în Next.js. Dacă endpoint-ul face procesare de imagini, scrie în cozi de mesaje, ține conexiuni de WebSocket deschise sau rulează cron-uri complexe, îi fac un microserviciu separat în Node.
Tu cum procedezi? Încă împingi toate integrările grele în /pages/api sau /app/api sau ai început să le separi în servicii dedicate?