Case study · Background job queue

Generating heavy reports on a schedule without blocking the app

Built on top of the Futurnu Node Job Queue Starter

Context

Imagine your product needs to generate heavy CSV or Excel reports for customers: usage exports, billing summaries, audit logs. Each report may take dozens of seconds or even minutes to build.

On top of that, product and operations teams also expect nightly email summaries and alert notifications whenever certain metrics cross a threshold.

If you try to generate these reports and alerts directly inside API requests, you end up with timeouts, frustrated users and a backend that is constantly under pressure.

مسئله

می‌خواهی برای هر مشتری گزارش‌های سنگین (مثلاً CSV چند ده هزار ردیفی یا فایل Excel با چند شیت) بسازی؛ اما اگر همین کار را در ریکوئست اصلی انجام بدهی، هم API کُند می‌شود و هم احتمال خطا و تایم‌اوت بالا می‌رود.

از طرفی نمی‌خواهی از صفر زیرساخت صف، ورکر و زمان‌بندی را خودت بسازی و با هر باگ ریز، نصف شب به‌خاطر اینسیدنت از خواب بپری.

در عمل یعنی هر بار که مشتری می‌خواهد گزارش تازه بگیرد، هم تو نگران فشار روی سیستم هستی و هم او باید منتظر بماند؛ اگر زیرساخت صف را درست جدا نکنی، هر دو طرف ناراضی می‌شوند.

How the starter helps

  • You get a Node.js worker app wired to Redis queues out of the box, with a clear file where you define jobs, so you only plug in your reporting logic instead of wiring infrastructure.
  • There is a pattern for scheduling recurring jobs (cron‑like) and for on‑demand jobs triggered from your main app, so both daily summaries and ad‑hoc exports share the same predictable pipeline.
  • The starter shows you how to structure job handlers, retries and logging so that long‑running work does not block user flows and you keep visibility into what is running in the background.
  • You can route both scheduled reports and alert notifications through the same queue pipeline, so spikes in emails or messages do not slow down the main application and you can tune worker capacity independently.

مسیر واقعی پیاده‌سازی

  1. برای هر نوع گزارش یک job handler تعریف می‌کنی (مثلاً generateUsageReport) که ورودی آن شناسهٔ کاربر یا سازمان است و خروجی‌اش یک فایل روی استوریج.
  2. در اپلیکیشن اصلی، به‌جای این‌که گزارش را همان‌جا بسازی، فقط یک job جدید در صف قرار می‌دهی و به کاربر می‌گویی بعد از آماده‌شدن لینک دانلود برایش ایمیل یا نوتیف ارسال می‌شود.
  3. برای گزارش‌های تکرارشونده (مثلاً گزارش هفتگی)، از قابلیت زمان‌بندی داخل استارتر استفاده می‌کنی تا در یک ساعت مشخص، برای تمام سازمان‌های فعال job ساخته شود.
  4. لاگ و متریک jobها را در همان ورکر نگه می‌داری تا اگر جایی fail شد، بتوانی retry، backoff و هشدار مناسب داشته باشی بدون این‌که به تجربهٔ کاربر در داشبورد لطمه بزند.
  5. در نهایت به‌جای این‌که هر گزارش سنگین را داخل ریکوئست اصلی هندل کنی، یک صف شفاف داری که می‌توانی ظرفیت ورکرها را بر اساس آن تنظیم کنی و API اصلی را برای درخواست‌های تعاملی سریع و پایدار نگه داری.

Sample queue snapshot

This is roughly what the queue looked like after a few weeks of running nightly reports and hourly alert checks for a small SaaS. The point is a steady flow of jobs with low failure rates and predictable worker usage, not giant volume.

Pending jobs

36

steady

Completed (last hour)

128

avg 14s/job

Failed (24h)

3

all retried

Active workers

4

1 reserved for scheduled jobs

در یک سناریوی واقعی می‌توانی وضعیت صف، تعداد jobهای در صف، متوسط زمان اجرا و تعداد خطاها را در یک داشبورد ساده ببینی و براساس آن تصمیم بگیری ظرفیت ورکرها را بالا یا پایین ببری، بدون این‌که لازم باشد این زیرساخت را از صفر طراحی کنی.

Outcome

With the Node Job Queue Starter, you separate heavy work like report generation, newsletters and clean‑up tasks from the main request/response cycle in a way that is observable and easy to reason about.

You spend your time deciding what to run and when, instead of debugging ad‑hoc worker scripts and hand‑rolled queues, while your users keep seeing a fast app even when large batches of reports are being prepared in the background.

In the reporting and alerting project behind this example, moving heavy workloads onto the queue reduced report related API timeouts from noticeable percentages to near zero, while nightly exports and alerts finished within a predictable window instead of drifting into working hours.