درخواست وب باید کوتاه و قابل پیش‌بینی باشد. ارسال چند ایمیل، پردازش فایل یا تماس با API کند این ویژگی را از بین می‌برد. Laravel Queue و Horizon کار را به پس‌زمینه می‌برند، اما قابل اعتماد بودن صف نتیجه طراحی job است، نه فقط اجرای worker.

چه کاری را به صف منتقل کنیم؟

اگر نتیجه برای پاسخ همین لحظه کاربر ضروری نیست، زمان آن متغیر است یا احتمال خطای سرویس بیرونی وجود دارد، queue گزینه خوبی است. ایمیل، تولید گزارش، resize تصویر، sync با CRM و پردازش webhook نمونه‌های معمول‌اند.

اما کاربر باید بداند درخواست پذیرفته شده است. برای export وضعیت «در حال آماده‌سازی» و اعلان پایان بهتر از spinner طولانی است.

payload کوچک و شناسه‌محور نگه دارید

به‌جای serialize کردن object بزرگ، ID و ورودی ضروری را داخل job بگذارید و داده تازه را هنگام اجرا بخوانید. البته باید تصمیم بگیرید job وضعیت زمان dispatch را لازم دارد یا وضعیت روز اجرا را؛ در امور مالی این تفاوت مهم است.

final class GenerateInvoicePdf implements ShouldQueue
{
    public function __construct(public int $invoiceId) {}

    public function handle(InvoicePdf $generator): void
    {
        $invoice = Invoice::query()->findOrFail($this->invoiceId);
        $generator->generate($invoice);
    }
}

Job باید اجرای دوباره را تحمل کند

بیشتر سیستم‌های صف تحویل «حداقل یک‌بار» دارند. worker ممکن است کار را انجام دهد اما پیش از ثبت موفقیت قطع شود و job دوباره اجرا شود. ارسال دوباره پرداخت یا ساخت رکورد تکراری نباید اتفاق بیفتد. unique constraint، کلید idempotency و ثبت وضعیت عملیات ابزارهای اصلی‌اند.

Retry فقط برای خطای موقت است

timeout شبکه و پاسخ 503 ممکن است با retry حل شوند؛ داده نامعتبر یا مجوز اشتباه نه. تعداد تلاش، backoff و سقف زمان را مشخص کنید. retry فوری و بی‌نهایت فقط سرویس خراب را بیشتر تحت فشار می‌گذارد.

برای هر job timeout کمی کوتاه‌تر از retry_after تنظیم کنید تا دو worker هم‌زمان یک job را اجرا نکنند. exceptionهای دائمی را fail کنید و context لازم را در log بگذارید.

صف‌ها را بر اساس اهمیت جدا کنید

اعلان ورود کاربر نباید پشت export چندگیگابایتی بماند. صف‌های high، default و heavy با worker و timeout متفاوت، کنترل ظرفیت را آسان می‌کنند. تعداد worker را فقط بالا نبرید؛ ببینید دیتابیس و API مقصد توان مصرف هم‌زمان را دارند یا نه.

Horizon چه چیزی به ما می‌دهد؟

Horizon نرخ پردازش، زمان اجرا، failed job و workload را قابل مشاهده می‌کند. tagگذاری job با tenant، order یا نوع عملیات پیدا کردن مشکل را سریع‌تر می‌کند. بااین‌حال داشبورد جای alert نیست. رشد طول صف، افزایش failure و زمان انتظار باید اعلان عملیاتی داشته باشند.

انتشار کد و worker قدیمی

worker فرایندی بلندمدت است و کد release قبلی را در حافظه دارد. بعد از deploy باید graceful restart شود. migration ناسازگار نیز می‌تواند job قدیمی را بشکند؛ تغییر دیتابیس را در چند مرحله سازگار منتشر کنید.

عملیات روزانه را از قبل طراحی کنید

  • failed job چه کسی را آگاه می‌کند؟
  • آیا replay امن است و دستور آن مستند شده؟
  • چه مدت payload و log نگهداری می‌شوند؟
  • در زمان قطعی Redis یا سرویس مقصد چه می‌کنیم؟

صف مطمئن بخشی از معماری مقیاس‌پذیر Laravel است. برای طراحی API و پردازش‌های غیرهمزمان یک محصول نیز صفحه خدمات معماری بک‌اند مسیر همکاری را توضیح می‌دهد.

پرسش‌های متداول

چه کاری باید به Queue منتقل شود؟

کاری که برای پاسخ فوری کاربر لازم نیست، زمان اجرا یا احتمال خطای بیرونی بالایی دارد؛ مثل ایمیل، پردازش فایل و اتصال کند به سرویس دیگر.

چرا یک Job دوبار اجرا می‌شود؟

بیشتر صف‌ها تحویل حداقل یک‌بار دارند. job باید idempotent طراحی شود تا اجرای مجدد نتیجه مخرب یا تکراری نسازد.