PromNET

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.

Queues — magyar Sidekiq-alternatíva, async-job runner CF-edge-en

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:

📝 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ó:

💡 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ételKöltség
💰 Operations (push + delivery)0.4 USD / 1M (első 1M / hó ingyen)
💰 Storage0.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:

✅ Mire IDEÁLIS?

🚀 Hogyan kezdj?

  1. /app/queues/uj → új queue létrehozás
  2. API-token generálás a /app/beallitasok/api-tokenek-en
  3. Push-API-t hívd a kódodból
  4. 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?

🎯 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

Hozzászólások

Betöltés…