هندسة البرمجيات

NestJS + Redis + BullMQ: تصميم Background Jobs موثوقة وقابلة لإعادة المحاولة

شرح تطبيقي لبناء مهام خلفية موثوقة في NestJS باستخدام Redis وBullMQ، مع Idempotency وRetries وDead-letter thinking ومراقبة التنفيذ.

Mohd Morad26 يوليو 2026آخر تحديث 30 يوليو 20262 دقائق0 مشاهدة
NestJS + Redis + BullMQ: تصميم Background Jobs موثوقة وقابلة لإعادة المحاولة
جدول المحتويات

عندما تصبح عملية ما أبطأ من أن تبقى داخل HTTP request، لا يكفي نقلها إلى Queue فقط؛ يجب تصميمها لتتحمل التكرار والانقطاع وإعادة المحاولة.

متى أستخدم Background Job؟

استخدم Job عندما تكون العملية مثل:

  • إرسال بريد أو Push Notification.
  • توليد تقرير أو PDF.
  • معالجة صور أو ملفات.
  • مزامنة بيانات مع نظام خارجي.
  • تنفيذ مهمة مجدولة.

مسار التنفيذ

Producer واضح وصغير

notifications.producer.ts
TypeScript
@Injectable()
export class NotificationsProducer {
  constructor(
    @InjectQueue('notifications')
    private readonly queue: Queue,
  ) {}
 
  enqueueWelcome(userId: string) {
    return this.queue.add('welcome-email', { userId }, {
      jobId: 'welcome:' + userId,
      attempts: 4,
      backoff: { type: 'exponential', delay: 2_000 },
      removeOnComplete: 500,
    });
  }
}

Worker آمن عند التكرار

notifications.processor.ts
TypeScript
@Processor('notifications')
export class NotificationsProcessor extends WorkerHost {
  async process(job: Job<{ userId: string }>) {
    const key = 'welcome-email:' + job.data.userId;
 
    const alreadySent = await this.deliveryRepo.exists(key);
    if (alreadySent) return { skipped: true };
 
    await this.mailer.sendWelcome(job.data.userId);
    await this.deliveryRepo.markDelivered(key);
 
    return { delivered: true };
  }
}

Retry ليس حلًا لكل خطأ

الخطأالإجراء المناسب
Timeout مؤقتRetry مع Backoff
429 Rate limitRetry بعد تأخير
Validation داخليFail بدون Retry
Resource deletedتعامل كحالة نهائية
External outageRetry + Alert بعد حد معين

مراقبة الطابور

  • عدد Jobs المنتظرة
  • عدد Failed jobs
  • مدة التنفيذ p95
  • Retry count
  • Alert عندما يتجاوز Queue lag حدًا تشغيليًا

يمكن دمج هذا النمط مع بنية SaaS قابلة للتوسع بدل إبقاء العمليات الثقيلة داخل الـ API.

الهدف ليس «استخدام Queue»، بل جعل الفشل متوقعًا وقابلًا للاسترداد.

عن الكاتب

Mohd Morad

أوثّق هنا القرارات الهندسية والدروس المستفادة من بناء المنتجات الرقمية.

مقالات ذات صلة