در یک پروژه واقعی Laravel، همه عملیات را نمیتوان یا نباید در همان لحظهای که کاربر درخواست خود را ارسال میکند اجرا کرد.
فرض کنید کاربر یک سفارش ثبت میکند و سیستم باید همزمان چند کار انجام دهد:
- ارسال ایمیل تأیید
- ارسال پیامک
- تولید فاکتور
- پردازش تصویر
- ارسال اطلاعات به یک API خارجی
- محاسبه گزارش
- بهروزرسانی اطلاعات چند جدول
- پردازش هزاران رکورد
اگر تمام این عملیات مستقیماً داخل Request اجرا شوند، کاربر باید تا پایان آنها منتظر بماند.
اینجاست که Queue در Laravel اهمیت پیدا میکند.
Queue به Laravel اجازه میدهد کارهای مختلف را در یک صف قرار دهد تا بعداً توسط یک Worker پردازش شوند.
به زبان ساده:
درخواست کاربر
↓
ثبت Job در Queue
↓
پاسخ سریع به کاربر
↓
Queue Worker
↓
اجرای Job
در این مقاله یاد میگیریم Queue در Laravel چیست، چگونه کار میکند، چه Driverهایی دارد، چگونه یک Queue با Database یا Redis راهاندازی کنیم، Worker چیست، چگونه Failed Jobها را مدیریت کنیم و چگونه Queue را در محیط Production اجرا کنیم.
# Queue در Laravel چیست؟
Queue یا صف، سیستمی برای قرار دادن کارهای قابل پردازش در یک صف انتظار است.
فرض کنید ۱۰۰۰ کار برای انجام داریم.
به جای اینکه برنامه بخواهد همه آنها را همزمان اجرا کند، میتوانیم آنها را داخل Queue قرار دهیم:
Job 1
Job 2
Job 3
Job 4
...
Job 1000
سپس یک یا چند Worker این Jobها را پردازش میکنند.
بنابراین Queue خودش معمولاً کار را انجام نمیدهد؛ بلکه Jobهای منتظر اجرا را نگهداری و در اختیار Worker قرار میدهد.
# Queue چه مشکلی را حل میکند؟
فرض کنید کاربر در سایت شما یک فرم ثبت سفارش ارسال میکند.
بدون Queue ممکن است چنین اتفاقی بیفتد:
ثبت سفارش
↓
ارسال ایمیل
↓
ارسال پیامک
↓
ارتباط با API
↓
ساخت PDF
↓
ثبت گزارش
↓
پاسخ به کاربر
اگر هر عملیات چند ثانیه طول بکشد، کاربر باید مدت زیادی منتظر بماند.
اما با Queue میتوانیم معماری را تغییر دهیم:
ثبت سفارش
↓
Dispatch Job
↓
قرار گرفتن Job در Queue
↓
پاسخ سریع به کاربر
و همزمان:
Queue Worker
↓
دریافت Job
↓
اجرای عملیات
این یکی از مهمترین دلایل استفاده از Queue در پروژههای Laravel است.
# تفاوت Job و Queue در Laravel چیست؟
این دو مفهوم ارتباط بسیار نزدیکی دارند اما یکسان نیستند.
Job مشخص میکند چه کاری باید انجام شود.
Queue مشخص میکند این کار در صف پردازش قرار بگیرد.
Worker کار موجود در Queue را دریافت و اجرا میکند.
برای مثال:
Job:
ProcessOrder
Queue:
لیست Jobهای منتظر اجرا
Worker:
پردازش ProcessOrder
میتوان این ساختار را اینگونه تصور کرد:
Application
↓
Job
↓
Queue
↓
Worker
↓
Execution
در مقاله قبلی به شکل کامل درباره Job در Laravel صحبت کردیم؛ در این مقاله تمرکز اصلی روی زیرساخت Queue و نحوه اجرای آن است.
# Queue Worker چیست؟
Worker برنامهای است که به Queue گوش میدهد و Jobهای موجود در آن را پردازش میکند.
برای اجرای Worker در Laravel معمولاً از دستور زیر استفاده میشود:
php artisan queue:work
پس از اجرای این دستور، Worker شروع میکند به بررسی Queue.
اگر Job جدیدی وجود داشته باشد، آن را دریافت و اجرا میکند.
به صورت ساده:
Queue
├── Job 1
├── Job 2
├── Job 3
└── Job 4
↓
Worker
↓
Execution
اگر Worker اجرا نشود، Jobهای Queue معمولاً منتظر میمانند تا یک Worker آنها را پردازش کند.
# Queue Driver چیست؟
Laravel از چند روش مختلف برای ذخیره و مدیریت Queue پشتیبانی میکند.
به این روشها Queue Driver گفته میشود.
بر اساس نیاز پروژه میتوان از Driverهای مختلف استفاده کرد.
مهمترین گزینههایی که معمولاً با آنها مواجه میشویم عبارتاند از:
| Driver | کاربرد |
|---|---|
sync | اجرای فوری و بدون صف واقعی |
database | ذخیره Queue در دیتابیس |
redis | استفاده از Redis برای Queue |
sqs | استفاده از Amazon SQS |
beanstalkd | استفاده از Beanstalkd |
برای پروژههای معمولی Laravel، database و redis گزینههای بسیار مهمی هستند.
# Queue Connection چیست؟
در Laravel تنظیمات Queue در فایل:
config/queue.php
قرار دارد.
اما معمولاً Connection اصلی را از فایل .env مشخص میکنیم.
مثلاً:
QUEUE_CONNECTION=database
یا:
QUEUE_CONNECTION=redis
و برای اجرای مستقیم:
QUEUE_CONNECTION=sync
بنابراین Laravel بر اساس QUEUE_CONNECTION متوجه میشود که Jobها را چگونه مدیریت کند.
# Queue با Driver sync
در حالت:
QUEUE_CONNECTION=sync
کارها عملاً در همان لحظه اجرا میشوند.
مثلاً:
ProcessOrder::dispatch($order->id);
در این حالت عملیات Job در همان Request انجام میشود.
پس:
Request
↓
Dispatch
↓
Job
↓
Execution
↓
Response
این حالت برای شروع توسعه یا پروژههای بسیار ساده مفید است، اما مزیت اصلی Queue یعنی پردازش پسزمینه را در اختیار ما قرار نمیدهد.
# Database Queue در Laravel
یکی از سادهترین روشهای راهاندازی Queue استفاده از Database است.
در این روش Laravel اطلاعات Jobهای منتظر اجرا را داخل یک جدول دیتابیس ذخیره میکند.
مزیت مهم این روش این است که برای شروع نیازی به نصب سرویس جداگانهای مانند Redis ندارید.
# ساخت جدول Queue
برای استفاده از Database Queue باید جدول مربوط به Queue را در دیتابیس داشته باشیم.
در نسخههای Laravel که از Migration مربوط به Queue استفاده میکنند، میتوانیم از Artisan کمک بگیریم:
php artisan make:queue-table
سپس Migrationها را اجرا میکنیم:
php artisan migrate
بعد از اجرای Migration، جدول Queue در دیتابیس ایجاد میشود.
در بسیاری از پروژهها جدولی مانند:
jobs
برای نگهداری Jobهای منتظر اجرا استفاده میشود.
# تنظیم Database Queue
در فایل .env:
QUEUE_CONNECTION=database
بعد از تغییر .env، اگر تنظیمات Configuration Cache شده باشد، بهتر است Cache مربوط به Configuration را پاک یا دوباره Cache کنیم:
php artisan config:clear
در محیط Production میتوان پس از بررسی تنظیمات از:
php artisan config:cache
استفاده کرد.
# اجرای Database Queue
حالا Worker را اجرا میکنیم:
php artisan queue:work
سپس در برنامه یک Job را Dispatch میکنیم:
ProcessOrder::dispatch($order->id);
Job وارد جدول Queue میشود.
Worker آن را پیدا میکند و اجرا خواهد کرد.
# چرخه اجرای Queue چگونه است؟
فرآیند کلی را میتوان اینگونه نمایش داد:
User Request
↓
Dispatch Job
↓
Queue Driver
↓
Store Job
↓
Queue Worker
↓
Get Job
↓
Execute handle()
↓
Delete Job
اگر اجرای Job موفق باشد، Job از صف حذف میشود.
اگر اجرای Job با خطا مواجه شود، Laravel بر اساس تنظیمات Retry و Failed Jobs با آن برخورد میکند.
# Redis Queue در Laravel چیست؟
Redis یکی از گزینههای بسیار محبوب برای Queue است.
Redis یک سیستم ذخیرهسازی داده در حافظه است که میتواند برای مدیریت Queue نیز استفاده شود.
در پروژههایی که حجم Queue بالا است یا به عملکرد بیشتری نیاز داریم، Redis میتواند انتخاب بسیار مناسبی باشد.
تنظیم Connection میتواند به شکل زیر باشد:
QUEUE_CONNECTION=redis
سپس Worker:
php artisan queue:work redis
را اجرا میکنیم.
البته برای استفاده از Redis باید Redis روی محیط اجرای پروژه در دسترس باشد و تنظیمات اتصال آن نیز صحیح باشد.
# Database Queue یا Redis Queue؟
هر دو روش کاربرد خودشان را دارند.
| ویژگی | Database | Redis |
|---|---|---|
| نصب ساده | بسیار ساده | نیازمند Redis |
| مناسب شروع | بله | بله |
| عملکرد بالا | متوسط | بسیار خوب |
| مناسب حجم بالا | محدودتر | مناسبتر |
| نیاز به سرویس جداگانه | خیر | بله |
| مدیریت Queueهای بزرگ | متوسط | بسیار مناسب |
| مناسب Production | بله | بله |
اگر پروژه کوچک یا متوسطی دارید و سادگی برایتان اهمیت دارد، Database Queue میتواند گزینه مناسبی باشد.
اگر پروژه حجم پردازش بالایی دارد و Redis از قبل در زیرساخت شما وجود دارد، Redis معمولاً انتخاب جذابتری است.
# Queue Worker را چگونه اجرا کنیم؟
دستور اصلی:
php artisan queue:work
این Worker به صورت دائمی به کار خود ادامه میدهد و Queue را پردازش میکند.
میتوان مشخصات مختلفی برای Worker تعیین کرد.
مثلاً:
php artisan queue:work --tries=3
یا:
php artisan queue:work --timeout=120
همچنین میتوان ترکیبی از گزینهها را استفاده کرد.
برای مثال:
php artisan queue:work --tries=3 --timeout=120
# queue:work و queue:listen چه تفاوتی دارند؟
Laravel دستورهای مختلفی برای اجرای Worker دارد.
یکی از دستورهای رایج:
php artisan queue:work
است.
queue:work برای محیطهای واقعی و Production گزینه متداولتری است، زیرا Worker را به شکل پایدار اجرا میکند.
در مقابل queue:listen معمولاً بیشتر در سناریوهای توسعه مورد استفاده قرار میگیرد و نسبت به queue:work سربار بیشتری دارد.
برای Production معمولاً بهتر است Worker پایدار را با یک Process Manager اجرا کنیم.
# اجرای Queue برای یک Queue مشخص
گاهی پروژه چند Queue مختلف دارد.
مثلاً:
default
emails
notifications
reports
میتوانیم Worker را برای Queue مشخص اجرا کنیم.
مثلاً:
php artisan queue:work --queue=emails
یا:
php artisan queue:work --queue=emails,notifications,default
در این حالت میتوانیم اولویت Queueها را نیز کنترل کنیم.
این قابلیت در پروژههایی که Jobهای مختلف با اهمیتهای متفاوت دارند بسیار مفید است.
# چرا چند Queue داشته باشیم؟
فرض کنید پروژه شما این Jobها را دارد:
SendEmail
GenerateReport
ProcessPayment
ResizeImage
SendNotification
پردازش پرداخت ممکن است بسیار مهمتر از Resize کردن یک تصویر باشد.
بنابراین میتوانیم Queueهای مختلف ایجاد کنیم:
high
default
low
و Jobها را در Queue مناسب قرار دهیم.
مثلاً:
ProcessPayment::dispatch($payment)
->onQueue('high');
یا:
GenerateReport::dispatch($report)
->onQueue('low');
سپس Worker را با اولویت مناسب اجرا کنیم:
php artisan queue:work --queue=high,default,low
# Retry در Queue چیست؟
ممکن است Job به دلیل یک خطای موقتی شکست بخورد.
برای مثال:
API خارجی در دسترس نیست
↓
Job شکست میخورد
↓
Retry
↓
API دوباره در دسترس است
↓
Job موفق میشود
میتوان تعداد تلاشها را مشخص کرد.
مثلاً:
public int $tries = 3;
یا هنگام اجرای Worker:
php artisan queue:work --tries=3
این موضوع باعث میشود خطاهای موقتی لزوماً باعث شکست نهایی Job نشوند.
# Failed Jobs در Laravel
گاهی Job بعد از تمام Retryها همچنان شکست میخورد.
در این حالت باید بتوانیم آن را بررسی کنیم.
Laravel امکان مدیریت Failed Jobs را فراهم میکند.
برای مشاهده Failed Jobs:
php artisan queue:failed
این دستور اطلاعات Jobهای شکستخورده را نمایش میدهد.
# Retry کردن Failed Job
اگر مشکل برطرف شده باشد، میتوانیم Job را دوباره اجرا کنیم:
php artisan queue:retry ID
برای مثال:
php artisan queue:retry 15
یا در صورت نیاز میتوان Jobهای بیشتری را Retry کرد.
این قابلیت در Production بسیار کاربردی است.
# پاک کردن Failed Jobs
اگر Job دیگر مورد نیاز نیست، میتوان آن را حذف کرد:
php artisan queue:forget ID
و برای پاکسازی Failed Jobs نیز میتوان از:
php artisan queue:flush
استفاده کرد.
# Queue Timeout چیست؟
فرض کنید یک Job به دلیل مشکل API یا پردازش بسیار سنگین برای مدت نامحدودی اجرا شود.
این موضوع میتواند Worker را برای مدت زیادی درگیر کند.
به همین دلیل باید Timeout مناسب داشته باشیم.
مثلاً:
php artisan queue:work --timeout=120
یا داخل Job:
public int $timeout = 120;
مقدار مناسب Timeout به نوع Job بستگی دارد.
# Queue و Jobهای سنگین
Queue برای پردازش کارهای سنگین بسیار مفید است.
برای مثال:
پردازش 100000 محصول
پردازش فایل Excel
تولید گزارش بزرگ
پردازش تصاویر
ارسال تعداد زیادی ایمیل
همگامسازی اطلاعات با API
بهتر است چنین کارهایی را به چند Job کوچکتر تقسیم کنیم.
مثلاً به جای:
Import100000ProductsJob
میتوانیم دادهها را به Batchهای کوچک تقسیم کنیم:
ImportProductsChunk 1
ImportProductsChunk 2
ImportProductsChunk 3
...
این کار مدیریت منابع را بسیار بهتر میکند.
# Queue و ارسال ایمیل
یکی از رایجترین کاربردهای Queue ارسال ایمیل است.
فرض کنید بعد از ثبت سفارش باید ایمیل ارسال شود.
به جای اینکه کاربر منتظر ارسال ایمیل بماند، میتوانیم ارسال ایمیل را Queue کنیم.
مثلاً:
SendOrderEmail::dispatch($order->id);
در این حالت:
ثبت سفارش
↓
پاسخ سریع
↓
Queue
↓
SendOrderEmail
↓
ارسال ایمیل
این معماری مخصوصاً در فروشگاههای اینترنتی بسیار کاربردی است.
# Queue و Notification
Notificationهای Laravel نیز میتوانند در معماری Queue استفاده شوند.
مثلاً فرض کنید باید برای هزار کاربر Notification ارسال کنیم.
به جای اینکه همه Notificationها را در Request اصلی اجرا کنیم، میتوانیم آنها را به پردازش غیرهمزمان بسپاریم.
این روش فشار روی Request اصلی را کاهش میدهد.
# Queue و APIهای خارجی
یکی از بهترین کاربردهای Queue، ارتباط با APIهای خارجی است.
فرض کنید بعد از ثبت محصول باید اطلاعات آن را به یک سرویس خارجی ارسال کنیم.
اگر API خارجی کند باشد:
Request
↓
API خارجی
↓
10 ثانیه انتظار
تجربه کاربر خراب میشود.
اما:
Request
↓
Dispatch Job
↓
Response
و بعد:
Worker
↓
API خارجی
باعث میشود سرعت پاسخ به کاربر مستقلتر از سرعت API خارجی شود.
# Queue و Jobهای Idempotent
یکی از نکات بسیار مهم در طراحی Queue این است که نباید فرض کنیم هر Job دقیقاً یک بار اجرا میشود.
ممکن است Job به دلایل مختلف دوباره اجرا شود.
بنابراین عملیات حساس باید تا حد امکان Idempotent باشند.
مثلاً در عملیات پرداخت نباید اجرای دوباره Job باعث ایجاد دو تراکنش شود.
بهتر است قبل از انجام عملیات بررسی کنیم که آیا قبلاً انجام شده است یا خیر.
مثلاً:
if ($payment->status === 'paid') {
return;
}
این موضوع در سیستمهای مالی اهمیت بسیار زیادی دارد.
# Queue و Database Transaction
یکی از موارد حساس، Dispatch کردن Job درون Transaction است.
مثلاً:
DB::transaction(function () use ($order) {
$order->update([
'status' => 'processing',
]);
ProcessOrder::dispatch($order->id);
});
اگر Worker بسیار سریع باشد، ممکن است Job قبل از Commit شدن Transaction اجرا شود.
در نتیجه باید در معماریهای حساس دقت کنیم Job چه زمانی قابل پردازش شود.
Laravel امکاناتی برای Dispatch کردن Job بعد از Commit شدن Transaction در اختیار توسعهدهنده قرار میدهد.
این موضوع مخصوصاً در پروژههای مالی، سفارش، موجودی و سیستمهای حساس اهمیت زیادی دارد.
# Queue Worker در Production
در محیط توسعه میتوانیم Worker را مستقیماً اجرا کنیم:
php artisan queue:work
اما در Production نمیتوانیم انتظار داشته باشیم یک ترمینال باز بماند و Worker همیشه فعال باشد.
اگر Process متوقف شود، Queue نیز متوقف خواهد شد.
بنابراین در Production باید Worker را با یک Process Manager مدیریت کنیم.
یکی از راهکارهای رایج استفاده از Supervisor است.
ساختار کلی:
Linux Server
↓
Supervisor
↓
Laravel Queue Worker
↓
Queue
Supervisor میتواند Worker را اجرا نگه دارد و اگر Worker متوقف شد، آن را دوباره اجرا کند.
# چرا نباید Queue Worker را فقط با SSH اجرا کنیم؟
فرض کنید با SSH وارد سرور شوید و اجرا کنید:
php artisan queue:work
اگر اتصال SSH قطع شود، بسته به نحوه اجرای Process ممکن است Worker نیز متوقف شود.
برای Production بهتر است اجرای Worker را به Process Manager بسپاریم.
به همین دلیل Supervisor یا راهکارهای مدیریت Process اهمیت زیادی دارند.
# Restart کردن Worker بعد از Deploy
یک نکته مهم در Production این است که Workerها Processهای طولانیمدت هستند.
اگر کد جدیدی Deploy کنیم، Worker قبلی ممکن است همچنان کد قبلی را در حافظه داشته باشد.
به همین دلیل بعد از Deploy معمولاً Workerها را Restart میکنیم:
php artisan queue:restart
این دستور به Workerها اعلام میکند پس از اتمام Job فعلی، خودشان را Restart کنند.
در نتیجه Workerهای جدید با نسخه جدید کد اجرا خواهند شد.
# Queue Worker و Memory Limit
Workerها ممکن است مدت زیادی فعال باشند.
اگر Jobها به مرور حافظه مصرف کنند، ممکن است Worker بیش از حد RAM مصرف کند.
برای همین میتوان Memory Limit تعیین کرد.
مثلاً:
php artisan queue:work --memory=512
در این حالت Worker در صورت عبور از محدوده مشخصشده، متوقف میشود تا Process Manager بتواند آن را دوباره راهاندازی کند.
این موضوع برای Production بسیار مهم است.
# Queue Worker و تعداد تلاشها
میتوانیم تعداد تلاش Job را از Worker نیز کنترل کنیم:
php artisan queue:work --tries=3
اما برای Jobهای مختلف ممکن است تعداد Retry متفاوتی نیاز داشته باشیم.
مثلاً:
Payment Job → 3 تلاش
Email Job → 5 تلاش
Report Job → 2 تلاش
به همین دلیل بهتر است سیاست Retry بر اساس اهمیت و ماهیت هر Job طراحی شود.
# مدیریت Queue با چند Worker
اگر تعداد Jobها زیاد باشد، یک Worker ممکن است کافی نباشد.
فرض کنید:
10000 Job
در Queue داریم.
یک Worker ممکن است نتواند آنها را با سرعت مناسب پردازش کند.
میتوان چند Worker اجرا کرد:
Worker 1 ──┐
Worker 2 ──┤
Worker 3 ──┼── Queue
Worker 4 ──┤
Worker 5 ──┘
در این حالت Jobها سریعتر پردازش میشوند.
تعداد Worker مناسب به مواردی مانند:
- CPU
- RAM
- تعداد Jobها
- زمان اجرای Job
- نوع عملیات
- نوع Queue Driver
بستگی دارد.
# Queue و Redis در پروژههای بزرگ
وقتی تعداد Jobها زیاد شود، Database Queue ممکن است دیگر بهترین انتخاب نباشد.
در چنین شرایطی Redis میتواند گزینه مناسبی باشد.
معماری میتواند چنین شکلی داشته باشد:
Laravel Application
↓
Redis
↓
Queue Jobs
↓
Worker 1
Worker 2
Worker 3
↓
Processing
Redis معمولاً در معماریهایی که تعداد زیادی Job باید با سرعت بالا پردازش شوند، کاربرد زیادی دارد.
در مقاله بعدی این کلاستر به شکل اختصاصی سراغ Redis در Laravel خواهیم رفت.
# Queue Monitoring چیست؟
در پروژههای Production فقط اجرای Queue کافی نیست.
باید بتوانیم وضعیت Queue را نیز بررسی کنیم.
مواردی که بهتر است مانیتور شوند عبارتاند از:
- تعداد Jobهای منتظر
- تعداد Jobهای شکستخورده
- زمان پردازش Job
- تعداد Retry
- وضعیت Workerها
- مصرف CPU
- مصرف RAM
- طول Queue
در پروژههای بزرگ، Monitoring Queue اهمیت زیادی پیدا میکند.
# Laravel Horizon چیست؟
برای پروژههایی که از Redis به عنوان Queue استفاده میکنند، Laravel Horizon یکی از ابزارهای مهم اکوسیستم Laravel است.
Horizon یک داشبورد و سیستم مدیریت برای Redis Queue در Laravel ارائه میکند.
با Horizon میتوان اطلاعاتی مانند:
- وضعیت Queue
- Jobهای پردازششده
- Jobهای شکستخورده
- زمان پردازش
- تعداد Jobها
- Workerها
را بهتر مشاهده و مدیریت کرد.
برای پروژههای کوچک ممکن است استفاده از Horizon ضروری نباشد، اما در پروژههایی که Queue اهمیت زیادی دارد میتواند بسیار ارزشمند باشد.
# Queueهای مختلف برای بخشهای مختلف سیستم
در پروژههای حرفهای بهتر است همه Jobها را داخل یک Queue قرار ندهیم.
مثلاً:
high
default
low
emails
reports
سپس Workerهای مختلف داشته باشیم:
Worker A → high
Worker B → default
Worker C → emails
Worker D → reports
این معماری باعث میشود عملیات مهمتر منابع مورد نیاز خود را داشته باشند.
مثلاً اگر تولید گزارش سنگین باشد، نباید باعث شود پردازش پرداختهای کاربران متوقف شود.
# اشتباهات رایج در استفاده از Queue
۱. اجرای Worker بدون Process Manager
در Production نباید فقط به یک Terminal وابسته باشیم.
۲. قرار دادن اطلاعات بسیار زیاد داخل Job
Job را تا حد امکان سبک نگه دارید و فقط اطلاعات مورد نیاز را منتقل کنید.
۳. نداشتن Timeout
Jobی که هیچ محدودیتی ندارد میتواند Worker را برای مدت زیادی اشغال کند.
۴. Retry نامناسب
Retry بیش از حد میتواند فشار بیشتری روی سیستم یا API خارجی ایجاد کند.
۵. نادیده گرفتن Failed Jobs
در Production باید Failed Jobs را بررسی و مانیتور کنیم.
۶. استفاده از یک Queue برای همه چیز
Jobهای مهم و کماهمیت بهتر است در صورت نیاز Queueهای جداگانه داشته باشند.
۷. فراموش کردن Restart Worker بعد از Deploy
Workerهای قدیمی ممکن است کد قدیمی را اجرا کنند.
پس بعد از Deploy باید چرخه Restart Worker را در فرآیند Deployment در نظر بگیریم.
۸. اجرای عملیات غیر Idempotent بدون کنترل
بهخصوص در پرداخت، موجودی و تراکنش مالی، اجرای دوباره Job میتواند مشکل جدی ایجاد کند.
# یک معماری پیشنهادی برای پروژه Laravel
برای یک پروژه متوسط میتوان چنین ساختاری داشت:
Laravel Application
│
├── Web Request
│
└── Dispatch Job
│
↓
Queue
│
┌───────┴───────┐
↓ ↓
Worker 1 Worker 2
│ │
└───────┬───────┘
↓
Job
↓
Service
↓
Database / API
اگر حجم سیستم بیشتر شود:
Laravel
↓
Redis
↓
Queue
↓
┌─────────┬─────────┬─────────┐
Worker 1 Worker 2 Worker 3
↓ ↓ ↓
Jobs Jobs Jobs
و برای مدیریت بهتر میتوان Horizon و Process Manager را نیز به این معماری اضافه کرد.
# چه زمانی از Database Queue استفاده کنیم؟
Database Queue گزینه مناسبی است اگر:
- پروژه کوچک یا متوسط است.
- Redis در دسترس ندارید.
- سادگی برایتان اهمیت دارد.
- حجم Queue خیلی زیاد نیست.
- نمیخواهید سرویس اضافی نصب کنید.
مثلاً برای یک سایت شرکتی یا فروشگاه متوسط ممکن است Database Queue کاملاً کافی باشد.
# چه زمانی Redis Queue انتخاب بهتری است؟
Redis معمولاً زمانی جذابتر میشود که:
- حجم Jobها زیاد باشد.
- سرعت Queue اهمیت زیادی داشته باشد.
- Workerهای متعدد داشته باشید.
- Redis از قبل در معماری پروژه استفاده شود.
- نیاز به Queue Monitoring حرفهای داشته باشید.
- پروژه مقیاسپذیر باشد.
برای پروژههای SaaS، Marketplace، سیستمهای اتوماسیون و سرویسهایی با پردازش زیاد، Redis میتواند انتخاب بسیار مناسبی باشد.
# راهاندازی سریع Database Queue
اگر بخواهیم یک نمونه ساده داشته باشیم:
مرحله اول: تنظیم Connection
در .env:
QUEUE_CONNECTION=database
مرحله دوم: ساخت جدول Queue
php artisan make:queue-table
مرحله سوم: اجرای Migration
php artisan migrate
مرحله چهارم: ساخت Job
php artisan make:job ProcessOrder
مرحله پنجم: Dispatch
ProcessOrder::dispatch($order->id);
مرحله ششم: اجرای Worker
php artisan queue:work
حالا Worker Job را دریافت و پردازش میکند.
# چگونه مطمئن شویم Queue کار میکند؟
یک Job آزمایشی ایجاد کنید:
php artisan make:job TestQueue
داخل handle():
public function handle(): void
{
\Log::info('Test Queue Job Executed');
}
سپس:
TestQueue::dispatch();
Worker را اجرا کنید:
php artisan queue:work
بعد فایل Log Laravel را بررسی کنید.
اگر پیام مربوط به Job را مشاهده کردید، Queue به درستی Job را پردازش کرده است.
# Queue در Laravel برای چه پروژههایی ضروری است؟
استفاده از Queue تقریباً در هر پروژه بزرگ Laravel اهمیت پیدا میکند، اما برای بعضی پروژهها اهمیت آن بسیار بیشتر است.
فروشگاه اینترنتی
برای:
- ایمیل سفارش
- پیامک
- فاکتور
- پردازش پرداخت
- همگامسازی محصولات
SaaS
برای:
- پردازش Subscription
- گزارشگیری
- Notification
- عملیات زمانبر
Marketplace
برای:
- پردازش سفارش
- محاسبه کمیسیون
- تسویه
- Notification
- گزارش فروش
سیستمهای اتوماسیون
برای:
- API
- Webhook
- پردازش داده
- اجرای Workflow
- ارتباط با سرویسهای خارجی
# جمعبندی
Queue در Laravel یکی از مهمترین ابزارها برای اجرای عملیات غیرهمزمان و مدیریت پردازشهای زمانبر است.
ساختار اصلی آن را میتوان اینگونه خلاصه کرد:
Job
↓
Queue
↓
Worker
↓
Execution
Laravel Driverهای مختلفی برای Queue ارائه میدهد و از جمله مهمترین گزینهها میتوان به:
syncdatabaseredissqsbeanstalkd
اشاره کرد.
برای پروژههای ساده، Database Queue میتواند انتخاب مناسبی باشد و برای پروژههای بزرگتر و پرترافیک، Redis معمولاً گزینه قدرتمندتری است.
اجرای Worker نیز با دستور:
php artisan queue:work
انجام میشود.
اما در Production بهتر است Worker را به یک Process Manager مانند Supervisor بسپاریم و مواردی مانند:
- Retry
- Timeout
- Failed Jobs
- Memory
- Restart
- چند Worker
- Queueهای مختلف
- Idempotency
را نیز به درستی مدیریت کنیم.
در نهایت، Queue فقط یک ابزار برای سریعتر شدن سایت نیست؛ بلکه بخشی از معماری یک برنامه Laravel حرفهای است که کمک میکند عملیات سنگین، زمانبر و غیرضروری برای Request اصلی از مسیر اجرای مستقیم خارج شوند.
سوالات متداول Queue در Laravel
Queue در Laravel چیست؟
Queue سیستمی برای قرار دادن Jobها در صف و پردازش آنها توسط Worker است.
چگونه Queue را در Laravel فعال کنیم؟
ابتدا باید QUEUE_CONNECTION را در .env تنظیم کنیم و سپس Driver موردنظر را پیکربندی کنیم.
چگونه Worker را اجرا کنیم؟
با دستور:
php artisan queue:work
Database Queue بهتر است یا Redis؟
برای پروژههای ساده و متوسط Database Queue میتواند کافی باشد؛ برای حجم پردازش بالاتر و معماریهای حرفهای، Redis معمولاً گزینه مناسبتری است.
اگر Queue Worker متوقف شود چه اتفاقی میافتد؟
Jobهای پردازشنشده در Queue باقی میمانند و پس از راهاندازی مجدد Worker میتوانند پردازش شوند؛ جزئیات رفتار به Driver و تنظیمات Job بستگی دارد.
چگونه Failed Jobها را مشاهده کنیم؟
با:
php artisan queue:failed
چگونه یک Failed Job را دوباره اجرا کنیم؟
با:
php artisan queue:retry ID
آیا Queue برای پروژههای کوچک لازم است؟
نه همیشه. اما حتی در پروژههای کوچک نیز برای عملیاتهایی مثل ارسال ایمیل، Notification یا ارتباط با API خارجی میتواند بسیار مفید باشد.
آیا Queue همان Job است؟
خیر. Job کاری است که باید انجام شود؛ Queue محل یا سازوکار صفبندی آن کار است و Worker وظیفه اجرای آن را بر عهده دارد.





