2026. május 8. · #queues #async #tutorial #cloudflare #developer
Queues — magyar Sidekiq-alternatíva, async-job runner CF-edge-en
Stripe-webhook utáni NAV-számla, batch-email-küldés, PDF-generálás — háttér-jobokra eddig vagy Sidekiq-Pro 99 USD/hó, vagy saját Redis. A PromNET Queues plugin Cloudflare Queues-on, kredit-alapon.
A modern webes-app nem akar mindent szinkronban csinálni. Ha 10 ezer
emailt kell küldened, vagy 500 PDF-et generálnod, vagy egy
Stripe-webhook után 3 másodperces NAV-számla-flow-t futtatnod —
háttér-job kell hozzá. Eddig erre vagy a Sidekiq-Pro-t fizetted
havi 99 USD/seat-en, vagy a saját Redis + worker-szervert
építgetted. A /app/queues plugin egy harmadik utat ad: CF Queues +
magyar UI.
⚠️ A klasszikus probléma
Tegyük fel, hogy a webshopod Stripe-checkout-ot használ. A webhook-handler-ed:
// /api/webhook/stripe.ts
export async function POST({ request }) {
const event = parseEvent(request);
if (event.type === "payment_intent.succeeded") {
await sendConfirmationEmail(event); // 800 ms
await generateInvoicePDF(event); // 2000 ms
await pushToNAV(event); // 1500 ms
await updateAccounting(event); // 600 ms
}
return new Response("ok"); // 4900 ms később...
}
⚠️ Probléma: a Stripe-webhook 5 másodperces timeoutot ad. Ha átléped, újrapróbálkozik, és a felhasználó kétszer kapja az emailt vagy a NAV-számlát. Tűzoltás-eset.
A “helyes” megoldás: a webhook-handler csak fogadja az eventet és queue-be tolja, a tényleges munkát háttérben csinálja egy worker.
// /api/webhook/stripe.ts — refactored
export async function POST({ request }) {
const event = parseEvent(request);
await pushToQueue("payment-flow", event); // 50 ms
return new Response("ok"); // gyors
}
✅ A queue-worker ezt a saját ütemében dolgozza fel — másodperc, perc, óra alatt, újrapróbálva ha valami fail-el, párhuzamosan.
🔄 A flow vizuálisan
sequenceDiagram
participant U as Stripe Webhook
participant W as Webhook Handler
participant Q as CF Queue
participant C as Consumer Worker
participant E as Email/PDF/NAV
U->>W: POST event (payment_succeeded)
W->>Q: push job (50 ms)
W-->>U: 200 OK (gyors!)
Q->>C: deliver batch (async)
C->>E: send email (800 ms)
C->>E: generate PDF (2000 ms)
C->>E: push to NAV (1500 ms)
C-->>Q: ack
🔧 A /app/queues plugin
A CF Queues egy megbízható üzenet-broker (mint a SQS, Redis-Streams, Kafka — csak edge-en, serverless-formában). A PromNET-plugin a gyakorlatban egyszerűsíti:
- ✅ Új queue létrehozás — UI-ról, név + leírás
- ✅ Push API — REST-en lökhetsz be jobs-okat
- ✅ Worker-CF Queue-binding — a saját Worker-ed fogyasztja
- 📊 Dashboard —
pending / processing / done / faileddarabszám - 🔄 Retry — fail-esetén max 3-szor újrapróbálva
- ⚠️ Dead-letter queue — ami 3-szor fail-elt, oda kerül (debug-céllal)
📝 Példa — email-batch küldés
Tegyük fel, hogy hetente 1× ki kell küldened egy hírlevelet 5000 ügyfélnek. Sync-flow: 5000 × 200 ms = 1000 másodperc (~17 perc). A felhasználói UI-d ennyit várna a “Küldés”-gomb után.
Async-flow Queues-zal:
1. Queue létrehozás
/app/queues/uj — név: email-batch, leírás: “Hírlevelek
async kiküldése”. Mentés.
2. Job-ok push-olása
A “Küldés”-gomb mögött:
// /api/admin/send-newsletter.ts
export async function POST({ request }) {
const subscribers = await getActiveSubscribers(); // 5000 user
for (const sub of subscribers) {
await fetch("https://api.promnet.hu/api/queues/email-batch/push", {
method: "POST",
headers: {
"Authorization": `Bearer ${API_TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
to: sub.email,
subject: "Heti hírlevél",
template: "newsletter-2026-05",
userId: sub.id,
})
});
}
return new Response("Queued: 5000 jobs"); // <2 másodperc
}
✅ A felhasználó 2 másodpercen belül kapja a “Sikeresen elindítva” üzenetet. A háttérben 5000 jobs várakozik a queue-ban.
3. Worker-fogyasztás
A worker-kódod a wrangler.toml-ban a queue-hoz kötve:
[[queues.consumers]]
queue = "email-batch"
max_batch_size = 10
max_batch_timeout = 5
A consumer-handler:
// worker/email-consumer.ts
export default {
async queue(batch, env) {
for (const message of batch.messages) {
const { to, subject, template, userId } = message.body;
try {
await sendEmailViaResend(to, subject, template);
message.ack(); // sikeres
} catch (err) {
if (message.attempts < 3) {
message.retry(); // 3-szor újrapróbálás
} else {
message.ack(); // 3 fail után dead-letter-be
}
}
}
}
};
⚡ A worker párhuzamosan, batchekben dolgozik. 5000 email kiküldése ~3-5 perc (a Resend rate-limitje korlátozza, nem a Queues).
🇭🇺 Példa — Stripe webhook flow
A bevezetőben említett scenárió, async-átdolgozva:
// /api/webhook/stripe.ts
export async function POST({ request }) {
const event = parseEvent(request);
if (event.type === "payment_intent.succeeded") {
await pushToQueue("payment-flow", {
type: "payment_succeeded",
paymentIntentId: event.data.object.id,
customerId: event.data.object.customer,
amount: event.data.object.amount,
});
}
return new Response("ok"); // <100 ms, Stripe boldog
}
A worker-handler:
// worker/payment-consumer.ts
export default {
async queue(batch, env) {
for (const message of batch.messages) {
const { type, paymentIntentId, customerId, amount } = message.body;
// 4 step, sync-ben hosszú lett volna, async-ban OK
await sendConfirmationEmail(customerId, amount);
const pdfUrl = await generateInvoicePDF(paymentIntentId);
await pushToNAV(paymentIntentId, pdfUrl);
await updateAccounting(paymentIntentId);
message.ack();
}
}
};
✅ A teljes flow háttérben fut, a felhasználó már 5 másodperccel korábban látta a “Köszönjük a vásárlást” oldalt.
📊 A dashboard
/app/queues/<queue-id> — látható:
- 📊 Pending — várakozó jobs
- ⚡ Processing — most fut
- ✅ Done (1h) — utolsó órában feldolgozott
- ❌ Failed — nem sikerült (3 retry után dead-letter-ben)
- 📊 Throughput-grafikon — perc / óra-bontásban
💡 Hibakeresésre: a failed jobs-ra kattintva látszik a payload + a hibaüzenet. Manuális retry vagy purge lehetséges.
💰 A Pricing
A CF Queues árazása:
| Tétel | Költség |
|---|---|
| 💰 Operations (push + delivery) | 0.4 USD / 1M (első 1M / hó ingyen) |
| 💰 Storage | 0.04 USD / GB / hó |
🇭🇺 Egy átlag-magyar SMB-webshop (havi 1000 megrendelés, 5 jobs / order = 5000 jobs/hó) havi 0 USD-be kerül.
✅ Egy nagy magyar webshop (havi 100k megrendelés = 500k jobs/hó) is 0 USD alatt marad.
A kreditegyenleged felé 0.5 kredit / 1000 jobs-ot számolunk — havi szinten elhanyagolható.
❌ Mire NEM való?
A Queues NEM:
- ❌ Sub-50ms reaktív flow — a queue-delivery latencyje ~100 ms - néhány perc. Ha azonnal kell, nincs queue, csak direkt API-hívás
- ❌ Globális FIFO-rendezés — a CF Queues per-shard FIFO, nem abszolút sorrend
- ❌ Komplex job-orchestrátor — ha lépcsős state-machine kell (job A után csak akkor B, ha valami történt), erre CF Workflows való, nem Queues
- ⚠️ Cron-scheduling — a queue csak push-ra reagál. Cron-ra külön: egy CF-Worker-cron (Cloudflare-natív cron-trigger, vagy CF-Workflows) hívja meg óránként a queue-push-API-t
✅ Mire IDEÁLIS?
- ✅ Email-batch (hírlevél, notification, password-reset)
- ✅ PDF-generálás (számla, bizonyítvány, jelentés)
- ✅ Webhook-flow (Stripe, GitHub, NAV-felé)
- ✅ Image-processing (thumbnail, resize, optimize)
- ✅ AI-flow (audio-átirat, embedding-kalkuláció — hosszú-futású)
- ✅ Adatbázis-import (CSV → D1 batch-insert)
🚀 Hogyan kezdj?
- /app/queues/uj → új queue létrehozás
- API-token generálás a
/app/beallitasok/api-tokenek-en - Push-API-t hívd a kódodból
- Saját CF Workert állíts be consumernek (vagy a beépített “PromNET-managed-consumer”-t kérd, és REST-callback-et kapsz minden message-ről — nem kell saját Worker)
💡 A “PromNET-managed-consumer” érdekes: ha nem akarsz saját Worker-t karbantartani, mi futtatjuk a consumer-kódot, és a te HTTP-endpointodat hívjuk minden jobra (mintha webhook lenne). Így bármilyen backend-stack (Node, Python, PHP, Ruby) tud queue-jobs-okat fogadni.
🔮 Mi jön ezután?
- Q2 2026 — Cron-scheduling UI (vizualis cron-builder)
- Q2 2026 — Webhook-managed-consumer beépített
- Q3 2026 — Workflow-orchestrátor (több-lépéses async)
- Q3 2026 — Job-priority (urgent / normal / low)
- Q4 2026 — Job-search & filter dashboard
🎯 Próbáld ki
/app/queues — első queue 30 másodperc alatt felállítható. Ha kérdés van, /community/dev fórumon vagy /app/support ticket.
Polyák Csaba
© 2026 PromNET — Polyák Csaba. ← Vissza a blog-ra
Betöltés…