صف ها
- معرفی
- ایجاد اشتغال
- میان افزار شغلی
- اعزام مشاغل
- Job Batching
- بسته شدن صف
- اجرای The Queue Worker
- پیکربندی سرپرست
- مقابله با مشاغل ناموفق
- پاک کردن مشاغل از صف
- نظارت بر صف های شما
- رویدادهای شغلی
معرفی
در حین ساختن برنامه وب خود، ممکن است وظایفی مانند تجزیه و ذخیره یک فایل CSV آپلود شده داشته باشید که انجام آنها در طول یک درخواست وب معمولی خیلی طول می کشد. خوشبختانه، لاراول به شما اجازه می دهد تا به راحتی مشاغل در صف ایجاد کنید که ممکن است در پس زمینه پردازش شوند. با انتقال وظایف زمان بر به صف، برنامه شما می تواند به درخواست های وب با سرعتی خیره کننده پاسخ دهد و تجربه کاربری بهتری را برای مشتریان شما فراهم کند.
صفهای لاراول یک API صف یکپارچه را در میان انواع پشتیبانهای صف مختلف، مانند Amazon SQS ، Redis ، یا حتی یک پایگاه داده رابطهای ارائه میکنند.
گزینه های پیکربندی صف لاراول در
config/queue.php
فایل پیکربندی برنامه شما ذخیره می شود. در این فایل، پیکربندیهای اتصال
برای هر یک از درایورهای صف را که با فریمورک موجود است، از جمله درایورهای پایگاه داده،
Amazon SQS
،
Redis
و
Beanstalkd
و همچنین یک درایور همزمان که وظایف را فوراً اجرا میکند (برای استفاده در
طول) پیدا خواهید کرد.
توسعه محلی). یک
null
راننده صف نیز گنجانده شده است که مشاغل در صف را کنار می گذارد.
لاراول اکنون Horizon، داشبورد و سیستم پیکربندی زیبا را برای صفهای مجهز به Redis شما ارائه میکند. برای اطلاعات بیشتر ، مستندات کامل Horizon را بررسی کنید .
اتصالات در مقابل صف ها
قبل از شروع کار با صف های لاراول، مهم است که تمایز بین "اتصالات" و "صف"
را درک کنید. در فایل پیکربندی شما
config/queue.php
، یک آرایه پیکربندی وجود دارد
connections
. این گزینه اتصالات به خدمات صف پشتیبان مانند Amazon SQS، Beanstalk یا
Redis را تعریف می کند. با این حال، هر اتصال صف داده شده ممکن است چندین "صف" داشته باشد که ممکن است به عنوان
پشته های مختلف یا انبوهی از کارهای صف در نظر گرفته شود.
توجه داشته باشید که هر مثال پیکربندی اتصال در
queue
فایل پیکربندی حاوی یک
queue
ویژگی است. این صف پیشفرض است که کارها هنگام ارسال به یک اتصال خاص به آن
ارسال میشوند. به عبارت دیگر، اگر یک کار را بدون مشخص کردن صریحاً مشخص کنید که باید به کدام صف ارسال شود، آن
کار در صفی که در
queue
ویژگی پیکربندی اتصال
تعریف شده است قرار میگیرد :
use App\Jobs\ProcessPodcast; // This job is sent to the default connection's default queue...ProcessPodcast::dispatch(); // This job is sent to the default connection's "emails" queue...ProcessPodcast::dispatch()->onQueue('emails');
برخی از برنامهها ممکن است نیازی به فشار دادن کارها به چند صف نداشته
باشند، در عوض ترجیح میدهند یک صف ساده داشته باشند. با این حال، فشار دادن کارها به صف های متعدد می تواند به
ویژه برای برنامه هایی مفید باشد که مایلند نحوه پردازش کارها را اولویت بندی یا تقسیم بندی کنند، زیرا کارگر صف
لاراول به شما اجازه می دهد تا مشخص کنید کدام صف ها را باید بر اساس اولویت پردازش کند. به عنوان مثال، اگر
مشاغل را به یک
high
صف فشار دهید، ممکن است کارگری را اجرا کنید که به آنها اولویت پردازش
بالاتری می دهد:
php artisan queue:work --queue=high,default
نکات و پیش نیازهای راننده
پایگاه داده
برای استفاده از
database
درایور صف، به یک جدول پایگاه داده برای نگهداری کارها نیاز دارید. برای
ایجاد مهاجرتی که این جدول را ایجاد می کند،
queue:table
دستور Artisan را اجرا کنید. پس از ایجاد مهاجرت، می توانید پایگاه داده خود
را با استفاده از
migrate
دستور مهاجرت کنید:
php artisan queue:table php artisan migrate
در نهایت، فراموش نکنید که
database
با به روز رسانی
QUEUE_CONNECTION
متغیر موجود در فایل برنامه، به برنامه خود دستور استفاده از درایور را
بدهید
.env
:
QUEUE_CONNECTION=database
ردیس
برای استفاده از
redis
درایور صف، باید یک اتصال پایگاه داده Redis را در
config/database.php
فایل پیکربندی خود پیکربندی کنید.
خوشه ردیس
اگر اتصال صف Redis شما از یک Redis Cluster استفاده میکند، نامهای صف شما باید حاوی تگ هش کلید باشند . این برای اطمینان از اینکه همه کلیدهای Redis برای یک صف معین در یک شکاف هش قرار میگیرند، لازم است:
'redis' => [ 'driver' => 'redis', 'connection' => 'default', 'queue' => '{default}', 'retry_after' => 90,],
مسدود کردن
هنگام استفاده از صف Redis، میتوانید از
block_for
گزینه پیکربندی استفاده کنید تا مشخص کنید راننده چه مدت باید منتظر بماند
تا یک کار قبل از تکرار از طریق حلقه کارگر و نظرسنجی مجدد پایگاه داده Redis باشد.
تنظیم این مقدار بر اساس بار صف می تواند کارآمدتر از نظرسنجی مداوم پایگاه
داده Redis برای کارهای جدید باشد. به عنوان مثال، می توانید مقدار را
5
برای نشان دادن اینکه درایور باید برای پنج ثانیه مسدود شود در حالی که
منتظر در دسترس قرار گرفتن یک کار است، تنظیم کنید:
'redis' => [ 'driver' => 'redis', 'connection' => 'default', 'queue' => 'default', 'retry_after' => 90, 'block_for' => 5,],
تنظیم
block_for
روی0
باعث میشود تا کارگران صف بهطور نامحدود مسدود شوند تا زمانی که کار در دسترس باشد. این همچنین از کنترل سیگنالهایی مانندSIGTERM
تا پردازش کار بعدی جلوگیری میکند.
سایر پیش نیازهای راننده
وابستگی های زیر برای درایورهای صف فهرست شده مورد نیاز است. این وابستگی ها ممکن است از طریق مدیر بسته Composer نصب شوند:
-
آمازون SQS:
aws/aws-sdk-php ~3.0
-
Beanstalkd:
pda/pheanstalk ~4.0
-
Redis:
predis/predis ~1.0
یا پسوند phpredis PHP
ایجاد اشتغال
ایجاد کلاس های شغلی
بهطور پیشفرض، تمام کارهای قابل صف برای برنامه شما در
app/Jobs
فهرست ذخیره میشوند. اگر
app/Jobs
دایرکتوری وجود نداشته باشد، با اجرای
make:job
دستور Artisan ایجاد می شود:
php artisan make:job ProcessPodcast
کلاس تولید شده
Illuminate\Contracts\Queue\ShouldQueue
اینترفیس را پیادهسازی میکند و به لاراول نشان میدهد که کار باید به صف
فشار داده شود تا به صورت ناهمزمان اجرا شود.
می توان با استفاده از انتشار خرد کار سفارشی کرد .
ساختار کلاس
کلاسهای کار بسیار ساده هستند، معمولاً فقط شامل یک
handle
متد هستند که زمانی که کار توسط صف پردازش میشود فراخوانی میشود. برای
شروع، بیایید نگاهی به یک کلاس شغلی بیاندازیم. در این مثال، وانمود میکنیم که یک سرویس انتشار پادکست را
مدیریت میکنیم و باید فایلهای پادکست آپلود شده را قبل از انتشار پردازش کنیم:
<?php namespace App\Jobs; use App\Models\Podcast;use App\Services\AudioProcessor;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Foundation\Bus\Dispatchable;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Queue\SerializesModels; class ProcessPodcast implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * The podcast instance. * * @var \App\Models\Podcast */ public $podcast; /** * Create a new job instance. * * @param App\Models\Podcast $podcast * @return void */ public function __construct(Podcast $podcast) { $this->podcast = $podcast; } /** * Execute the job. * * @param App\Services\AudioProcessor $processor * @return void */ public function handle(AudioProcessor $processor) { // Process uploaded podcast... }}
در این مثال، توجه داشته باشید که ما توانستیم یک
مدل Eloquent را
مستقیماً به سازنده کار در صف ارسال کنیم. به دلیل
SerializesModels
ویژگیای که کار از آن استفاده میکند، مدلهای Eloquent و روابط بارگذاری
شده آنها بهخوبی سریالسازی میشوند و در هنگام پردازش کار، سریالسازی نمیشوند.
اگر کار در صف شما یک مدل Eloquent را در سازنده خود بپذیرد، فقط شناسه مدل در صف سریال قرار می گیرد. هنگامی که کار واقعاً انجام می شود، سیستم صف به طور خودکار نمونه کامل مدل و روابط بارگذاری شده آن را از پایگاه داده بازیابی می کند. این رویکرد به سریال سازی مدل اجازه می دهد تا محموله های کار بسیار کوچکتری به راننده صف شما ارسال شود.
handle
روش تزریق وابستگی
این
handle
روش زمانی فراخوانی می شود که کار توسط صف پردازش شود. توجه داشته باشید که
میتوانیم وابستگیهای مربوط به
handle
روش کار را تایپ کنیم.
ظرف سرویس
لاراول
به طور خودکار این وابستگی ها را تزریق می کند.
اگر میخواهید کنترل کاملی بر نحوه تزریق وابستگیهای کانتینر به
handle
روش در دست بگیرید، میتوانید از روش ظرف استفاده کنید
bindMethod
. متد
bindMethod
یک callback را می پذیرد که کار و کانتینر را دریافت می کند. در بازخوانی،
شما آزاد هستید که
handle
روش را هر طور که می خواهید فراخوانی کنید. به طور معمول، شما باید این روش
را از روش
ارائه دهنده خدمات
boot
خود فراخوانی کنید
:
App\Providers\AppServiceProvider
use App\Jobs\ProcessPodcast;use App\Services\AudioProcessor; $this->app->bindMethod([ProcessPodcast::class, 'handle'], function ($job, $app) { return $job->handle($app->make(AudioProcessor::class));});
داده های باینری، مانند محتویات تصویر خام، باید
base64_encode
قبل از ارسال به یک کار در صف، از طریق تابع ارسال شوند. در غیر این صورت، کار ممکن است به درستی به JSON تبدیل نشود، زمانی که در صف قرار میگیرد.
روابط در صف
از آنجایی که روابط بارگذاری شده نیز سریالی می شوند، رشته شغلی سریالی می
تواند گاهی اوقات بسیار بزرگ شود. برای جلوگیری از سریالسازی روابط، میتوانید
withoutRelations
هنگام تنظیم مقدار ویژگی، متد را روی مدل فراخوانی کنید. این روش نمونه ای
از مدل را بدون روابط بارگذاری شده آن برمی گرداند:
/** * Create a new job instance. * * @param \App\Models\Podcast $podcast * @return void */public function __construct(Podcast $podcast){ $this->podcast = $podcast->withoutRelations();}
علاوه بر این، هنگامی که یک کار از حالت سریال خارج می شود و روابط مدل مجدداً از پایگاه داده بازیابی می شوند، به طور کامل بازیابی می شوند. هر گونه محدودیت رابطه قبلی که قبل از سریال سازی مدل در طول فرآیند صف کار اعمال شده بود، در زمانی که کار غیراصولی شود، اعمال نخواهد شد. بنابراین، اگر میخواهید با زیرمجموعهای از یک رابطه معین کار کنید، باید دوباره آن رابطه را در شغل صف خود محدود کنید.
مشاغل منحصر به فرد
مشاغل منحصر به فرد نیاز به یک درایور حافظه پنهان دارند که از قفل ها پشتیبانی می کند . در حال حاضر، درایورهای
memcached
,redis
,dynamodb
,database
,file
وarray
کش از قفل اتمی پشتیبانی می کنند. علاوه بر این، محدودیتهای شغلی منحصربهفرد برای مشاغل درون دستهای اعمال نمیشود.
گاهی اوقات، ممکن است بخواهید مطمئن شوید که تنها یک نمونه از یک کار خاص در
هر نقطه از زمان در صف است. می توانید این کار را با پیاده سازی
ShouldBeUnique
رابط در کلاس شغلی خود انجام دهید. این رابط نیازی به تعریف هیچ روش اضافی
در کلاس خود ندارد:
<?php use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Contracts\Queue\ShouldBeUnique; class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique{ ...}
در مثال بالا،
UpdateSearchIndex
کار منحصر به فرد است. بنابراین، اگر نمونه دیگری از کار از قبل در صف باشد
و پردازش تمام نشده باشد، کار ارسال نخواهد شد.
در موارد خاص، ممکن است بخواهید «کلید» خاصی را تعریف کنید که کار را
منحصربهفرد میکند یا ممکن است بخواهید زمانی را مشخص کنید که پس از آن کار دیگر منحصربهفرد باقی نمیماند.
برای انجام این کار، میتوانید ویژگیها یا روشهایی را در کلاس شغلی خود تعریف
uniqueId
کنید
uniqueFor
:
<?php use App\Models\Product;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Contracts\Queue\ShouldBeUnique; class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique{ /** * The product instance. * * @var \App\Product */ public $product; /** * The number of seconds after which the job's unique lock will be released. * * @var int */ public $uniqueFor = 3600; /** * The unique ID of the job. * * @return string */ public function uniqueId() { return $this->product->id; }}
در مثال بالا،
UpdateSearchIndex
کار با شناسه محصول منحصر به فرد است. بنابراین، هر گونه ارسال جدید از کار
با همان شناسه محصول نادیده گرفته می شود تا زمانی که کار موجود پردازش را تکمیل کند. علاوه بر این، اگر کار
موجود ظرف یک ساعت پردازش نشود، قفل منحصربهفرد آزاد میشود و کار دیگری با همان کلید یکتا به صف ارسال میشود.
اگر برنامه شما کارها را از چندین وب سرور یا کانتینر ارسال می کند، باید اطمینان حاصل کنید که همه سرورهای شما با یک سرور کش مرکزی یکسان در ارتباط هستند تا لاراول بتواند به طور دقیق تشخیص دهد که آیا یک کار منحصر به فرد است یا خیر.
منحصر به فرد نگه داشتن مشاغل تا زمان شروع پردازش
بهطور پیشفرض، مشاغل منحصربهفرد پس از تکمیل پردازش یا شکست تمام
تلاشهای مجدد آن، «باز» میشوند. با این حال، ممکن است شرایطی وجود داشته باشد که بخواهید قفل کارتان بلافاصله
قبل از پردازش آن باز شود. برای انجام این کار، شغل شما باید
ShouldBeUniqueUntilProcessing
به جای
ShouldBeUnique
قرارداد، قرارداد را اجرا کند:
<?php use App\Models\Product;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Contracts\Queue\ShouldBeUniqueUntilProcessing; class UpdateSearchIndex implements ShouldQueue, ShouldBeUniqueUntilProcessing{ // ...}
قفل های شغلی منحصر به فرد
در پشت صحنه، هنگامی که یک
ShouldBeUnique
کار ارسال می شود، لاراول تلاش می کند تا یک
قفل را
با
uniqueId
کلید بدست آورد. اگر قفل به دست نیامد، کار ارسال نمی شود. این قفل زمانی
آزاد می شود که کار پردازش کامل شود یا تمام تلاش های مجدد آن با شکست مواجه شود. به طور پیش فرض، لاراول از
درایور کش پیش فرض برای به دست آوردن این قفل استفاده می کند. با این حال، اگر میخواهید از درایور دیگری برای
به دست آوردن قفل استفاده کنید، میتوانید روشی را تعریف کنید
uniqueVia
که درایور کش را که باید استفاده شود برمیگرداند:
use Illuminate\Support\Facades\Cache; class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique{ ... /** * Get the cache driver for the unique job lock. * * @return \Illuminate\Contracts\Cache\Repository */ public function uniqueVia() { return Cache::driver('redis'); }}
اگر فقط باید پردازش همزمان یک کار را محدود کنید،
WithoutOverlapping
به جای آن از میان افزار کار استفاده کنید.
میان افزار شغلی
میانافزارهای شغلی به شما این امکان را میدهند که منطق سفارشی را حول
اجرای کارهای در صف بپیچید، و باعث کاهش حجم دیگ در خود کارها میشود. به عنوان مثال، روش زیر را در نظر بگیرید
handle
که از ویژگیهای محدودکننده نرخ Redis لاراول استفاده میکند تا فقط یک کار
را هر پنج ثانیه پردازش کند:
use Illuminate\Support\Facades\Redis; /** * Execute the job. * * @return void */public function handle(){ Redis::throttle('key')->block(0)->allow(1)->every(5)->then(function () { info('Lock obtained...'); // Handle job... }, function () { // Could not obtain lock... return $this->release(5); });}
در حالی که این کد معتبر است، پیاده سازی روش
handle
نویزدار می شود زیرا با منطق محدود کننده نرخ Redis درهم است. علاوه بر این،
این منطق محدود کننده نرخ باید برای هر شغل دیگری که میخواهیم رتبهبندی کنیم، تکرار شود.
به جای محدود کردن نرخ در روش دسته، میتوانیم یک میانافزار شغلی تعریف
کنیم که محدودیت نرخ را مدیریت میکند. لاراول مکان پیشفرضی برای میانافزار شغلی ندارد، بنابراین میتوانید
میانافزار شغلی را در هر جایی از برنامه خود قرار دهید. در این مثال، میان افزار را در یک دایرکتوری قرار می
دهیم
app/Jobs/Middleware
:
<?php namespace App\Jobs\Middleware; use Illuminate\Support\Facades\Redis; class RateLimited{ /** * Process the queued job. * * @param mixed $job * @param callable $next * @return mixed */ public function handle($job, $next) { Redis::throttle('key') ->block(0)->allow(1)->every(5) ->then(function () use ($job, $next) { // Lock obtained... $next($job); }, function () use ($job) { // Could not obtain lock... $job->release(5); }); }}
همانطور که میبینید، مانند میانافزار مسیر ، میانافزار شغلی کار در حال پردازش را دریافت میکند و یک فراخوانی که باید برای ادامه پردازش کار فراخوانی شود.
پس از ایجاد میانافزار شغل، ممکن است با بازگرداندن آنها از روش کار، به یک
شغل متصل شوند
middleware
. این روش در مشاغل دارای داربست با دستور Artisan وجود ندارد
make:job
، بنابراین باید به صورت دستی آن را به کلاس شغلی خود اضافه کنید:
use App\Jobs\Middleware\RateLimited; /** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [new RateLimited];}
میانافزار شغلی را میتوان به شنوندههای رویداد، پیامهای پستی و اعلانها نیز اختصاص داد.
محدود کردن نرخ
اگرچه ما به تازگی نشان دادیم که چگونه می توان میان افزار شغلی محدود کننده
نرخ خود را بنویسید، لاراول در واقع شامل یک میان افزار محدود کننده نرخ است که ممکن است برای رتبه بندی مشاغل
محدود از آن استفاده کنید. مانند
محدود کننده های نرخ مسیر
، محدود کننده های نرخ کار با استفاده از روش
RateLimiter
نما تعریف می شوند
for
.
به عنوان مثال، ممکن است بخواهید به کاربران اجازه دهید یک بار در ساعت از
داده های خود نسخه پشتیبان تهیه کنند، در حالی که چنین محدودیتی برای مشتریان ممتاز اعمال نمی شود. برای انجام
این کار، می توانید a را
RateLimiter
در
boot
متد خود تعریف کنید
AppServiceProvider
:
use Illuminate\Cache\RateLimiting\Limit;use Illuminate\Support\Facades\RateLimiter; /** * Bootstrap any application services. * * @return void */public function boot(){ RateLimiter::for('backups', function ($job) { return $job->user->vipCustomer() ? Limit::none() : Limit::perHour(1)->by($job->user->id); });}
در مثال بالا، ما محدودیت نرخ ساعتی را تعریف کردیم. با این حال، می توانید
به راحتی با استفاده از
perMinute
روش، محدودیت نرخ را بر اساس دقیقه تعریف کنید. علاوه بر این، میتوانید هر
مقداری را که میخواهید به
by
روش محدودیت نرخ ارسال کنید. با این حال، این مقدار اغلب برای بخش بندی
محدودیت های نرخ توسط مشتری استفاده می شود:
return Limit::perMinute(50)->by($job->user->id);
هنگامی که محدودیت نرخ خود را تعیین کردید، می توانید با استفاده از
Illuminate\Queue\Middleware\RateLimited
میان افزار، محدود کننده نرخ را به کار پشتیبان خود متصل کنید. هر بار که
کار از حد مجاز تجاوز می کند، این میان افزار کار را با تاخیر مناسب بر اساس مدت زمان محدودیت نرخ، به صف باز می
گرداند.
use Illuminate\Queue\Middleware\RateLimited; /** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [new RateLimited('backups')];}
بازگرداندن یک کار با نرخ محدود دوباره در صف، تعداد کل کار را افزایش می
دهد
attempts
. ممکن است بخواهید بر اساس آن، ویژگی های خود
tries
و
maxExceptions
طبقه شغلی خود را تنظیم کنید. یا، ممکن است بخواهید از این
retryUntil
روش
برای تعیین مدت زمانی استفاده کنید که کار دیگر نباید انجام شود.
اگر نمی خواهید یک کار زمانی که دارای نرخ محدود است دوباره امتحان شود، می
توانید از
dontRelease
روش زیر استفاده کنید:
/** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [(new RateLimited('backups'))->dontRelease()];}
اگر از Redis استفاده میکنید، میتوانید از
Illuminate\Queue\Middleware\RateLimitedWithRedis
میانافزار استفاده کنید که برای Redis بهخوبی تنظیم شده است و از میانافزار محدودکننده نرخ پایه کارآمدتر است.
جلوگیری از همپوشانی مشاغل
لاراول شامل یک
Illuminate\Queue\Middleware\WithoutOverlapping
میان افزار است که به شما امکان می دهد از همپوشانی کار بر اساس یک کلید
دلخواه جلوگیری کنید. این می تواند مفید باشد زمانی که یک کار در صف در حال تغییر منبعی است که فقط باید توسط یک
کار در یک زمان اصلاح شود.
به عنوان مثال، بیایید تصور کنیم که یک کار در صف دارید که امتیاز اعتبار یک
کاربر را به روز می کند و می خواهید از همپوشانی کار به روز رسانی امتیاز اعتبار برای همان شناسه کاربری جلوگیری
کنید. برای انجام این کار، می توانید
WithoutOverlapping
میان افزار را از روش شغل خود برگردانید
middleware
:
use Illuminate\Queue\Middleware\WithoutOverlapping; /** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [new WithoutOverlapping($this->user->id)];}
هر گونه کار همپوشانی از همان نوع به صف بازگردانده می شود. همچنین میتوانید تعداد ثانیههایی را که باید قبل از انجام دوباره کار آزاد شده سپری شود را مشخص کنید:
/** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [(new WithoutOverlapping($this->order->id))->releaseAfter(60)];}
اگر میخواهید فوراً کارهای همپوشانی را حذف کنید تا دوباره امتحان نشوند،
میتوانید از
dontRelease
روش زیر استفاده کنید:
/** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [(new WithoutOverlapping($this->order->id))->dontRelease()];}
میان
WithoutOverlapping
افزار از ویژگی قفل اتمی لاراول تغذیه می شود. گاهی اوقات، کار شما ممکن است
به طور غیرمنتظره ای از کار بیفتد یا به گونه ای به پایان برسد که قفل باز نشود. بنابراین، می توانید با استفاده
از روش، زمان انقضای قفل را به صراحت تعریف کنید
expireAfter
. به عنوان مثال، مثال زیر به لاراول دستور می دهد که
WithoutOverlapping
قفل را سه دقیقه پس از شروع پردازش کار آزاد کند:
/** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [(new WithoutOverlapping($this->order->id))->expireAfter(180)];}
میان
WithoutOverlapping
افزار به یک درایور کش نیاز دارد که از قفل ها پشتیبانی می کند . در حال حاضر، درایورهایmemcached
,redis
,dynamodb
,database
,file
وarray
کش از قفل اتمی پشتیبانی می کنند.
به اشتراک گذاری کلیدهای قفل در کلاس های شغلی
بهطور پیشفرض،
WithoutOverlapping
میانافزار فقط از همپوشانی مشاغل همرده جلوگیری میکند. بنابراین، اگرچه
ممکن است دو کلاس شغلی مختلف از یک کلید قفل استفاده کنند، اما از همپوشانی آنها جلوگیری نخواهد شد. با این حال،
میتوانید به لاراول دستور دهید تا کلید را در کلاسهای شغلی با استفاده از
shared
روش زیر اعمال کند:
use Illuminate\Queue\Middleware\WithoutOverlapping; class ProviderIsDown{ // ... public function middleware() { return [ (new WithoutOverlapping("status:{$this->provider}"))->shared(), ]; }} class ProviderIsUp{ // ... public function middleware() { return [ (new WithoutOverlapping("status:{$this->provider}"))->shared(), ]; }}
استثنائات تروتتلینگ
لاراول شامل یک
Illuminate\Queue\Middleware\ThrottlesExceptions
میان افزار است که به شما امکان می دهد استثنائات را کاهش دهید. هنگامی که
کار تعداد معینی از استثناها را ایجاد می کند، تمام تلاش های بعدی برای اجرای کار تا زمانی که یک بازه زمانی
مشخص سپری شود به تعویق می افتد. این میان افزار به ویژه برای مشاغلی که با سرویس های شخص ثالث که ناپایدار
هستند در تعامل هستند مفید است.
به عنوان مثال، بیایید یک کار در صف را تصور کنیم که با یک API شخص ثالث
تعامل دارد که شروع به ایجاد استثنا می کند. برای کاهش دریچه گاز، می توانید
ThrottlesExceptions
میان افزار را از روش کار خود برگردانید
middleware
. به طور معمول، این میان افزار باید با کاری که
تلاش های مبتنی بر زمان را
اجرا می کند جفت شود :
use Illuminate\Queue\Middleware\ThrottlesExceptions; /** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [new ThrottlesExceptions(10, 5)];} /** * Determine the time at which the job should timeout. * * @return \DateTime */public function retryUntil(){ return now()->addMinutes(5);}
اولین آرگومان سازنده پذیرفته شده توسط میانافزار تعداد استثناهایی است که کار میتواند قبل از throttle شدن ایجاد کند، در حالی که آرگومان سازنده دوم تعداد دقیقههایی است که باید قبل از انجام دوباره کار پس از پایان دادن به آن بگذرد. در مثال کد بالا، اگر کار 10 استثنا را در عرض 5 دقیقه پرتاب کند، 5 دقیقه قبل از تلاش مجدد کار صبر می کنیم.
هنگامی که یک کار یک استثنا ایجاد می کند اما آستانه استثنا هنوز به آن
نرسیده است، معمولاً کار بلافاصله دوباره امتحان می شود. با این حال، میتوانید با فراخوانی
backoff
روش هنگام اتصال میانافزار به کار،
تعداد دقیقههایی که چنین کاری باید به تأخیر بیفتد را مشخص کنید :
use Illuminate\Queue\Middleware\ThrottlesExceptions; /** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [(new ThrottlesExceptions(10, 5))->backoff(5)];}
در داخل، این میانافزار از سیستم کش لاراول برای اجرای محدود کردن نرخ
استفاده میکند و نام کلاس کار به عنوان «کلید» حافظه پنهان استفاده میشود. می توانید با فراخوانی
by
روش هنگام اتصال میان افزار به شغل خود، این کلید را لغو کنید. این ممکن است
مفید باشد اگر چندین شغل دارید که با یک سرویس شخص ثالث در حال تعامل هستند و دوست دارید آنها یک "سطل گاز"
مشترک را به اشتراک بگذارند:
use Illuminate\Queue\Middleware\ThrottlesExceptions; /** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [(new ThrottlesExceptions(10, 10))->by('key')];}
اگر از Redis استفاده میکنید، میتوانید از
Illuminate\Queue\Middleware\ThrottlesExceptionsWithRedis
میانافزار استفاده کنید، که برای Redis بهخوبی تنظیم شده است و از میانافزار استثنایی اصلی کارآمدتر است.
اعزام مشاغل
هنگامی که کلاس شغلی خود را نوشتید، می توانید آن را با استفاده از
dispatch
روش خود کار ارسال کنید. آرگومان های ارسال شده به
dispatch
متد به سازنده کار داده می شود:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use App\Models\Podcast;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $podcast = Podcast::create(/* ... */); // ... ProcessPodcast::dispatch($podcast); }}
اگر می خواهید کاری را به صورت مشروط ارسال کنید، می توانید از روش های
dispatchIf
زیر استفاده کنید
dispatchUnless
:
ProcessPodcast::dispatchIf($accountActive, $podcast); ProcessPodcast::dispatchUnless($accountSuspended, $podcast);
در برنامه های جدید لاراول،
sync
درایور درایور صف پیش فرض است. این درایور کارها را به صورت همزمان در پیش
زمینه درخواست فعلی اجرا می کند، که اغلب در طول توسعه محلی راحت است. اگر میخواهید در واقع کارهای صف را برای
پردازش پسزمینه شروع کنید، میتوانید درایور صف متفاوتی را در
config/queue.php
فایل پیکربندی
برنامه خود تعیین کنید .
ارسال با تاخیر
اگر می خواهید مشخص کنید که یک کار نباید فوراً برای پردازش توسط یک کارگر
صف در دسترس باشد، می توانید از این
delay
روش هنگام ارسال کار استفاده کنید. به عنوان مثال، اجازه دهید مشخص کنیم که
یک کار نباید تا 10 دقیقه پس از ارسال آن برای پردازش در دسترس باشد:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use App\Models\Podcast;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $podcast = Podcast::create(/* ... */); // ... ProcessPodcast::dispatch($podcast) ->delay(now()->addMinutes(10)); }}
سرویس صف آمازون SQS دارای حداکثر زمان تاخیر 15 دقیقه است.
ارسال پس از ارسال پاسخ به مرورگر
از طرف دیگر، اگر سرور وب شما از FastCGI استفاده می کند، این
dispatchAfterResponse
روش ارسال یک کار را تا زمانی که پاسخ HTTP به مرورگر کاربر ارسال شود به
تأخیر می اندازد. این همچنان به کاربر اجازه می دهد تا استفاده از برنامه را شروع کند، حتی اگر یک کار در صف
هنوز در حال اجرا باشد. این معمولاً باید فقط برای کارهایی استفاده شود که حدود یک ثانیه طول می کشد، مانند
ارسال ایمیل. از آنجایی که آنها در درخواست فعلی HTTP پردازش می شوند، کارهایی که به این روش ارسال می شوند
نیازی به اجرای صف کارگر ندارند تا پردازش شوند:
use App\Jobs\SendNotification; SendNotification::dispatchAfterResponse();
همچنین میتوانید روش را
dispatch
ببندید و
afterResponse
به
dispatch
کمک زنجیر کنید تا پس از ارسال پاسخ HTTP به مرورگر، بسته شدن را اجرا کنید:
use App\Mail\WelcomeMessage;use Illuminate\Support\Facades\Mail; dispatch(function () { Mail::to('taylor@example.com')->send(new WelcomeMessage);})->afterResponse();
دیسپاچینگ همزمان
اگر می خواهید یک کار را فوراً (به طور همزمان) ارسال کنید، می توانید از
این
dispatchSync
روش استفاده کنید. هنگام استفاده از این روش، کار در صف قرار نمی گیرد و
بلافاصله در فرآیند فعلی اجرا می شود:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use App\Models\Podcast;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $podcast = Podcast::create(/* ... */); // Create podcast... ProcessPodcast::dispatchSync($podcast); }}
مشاغل و معاملات پایگاه داده
در حالی که ارسال کارها در تراکنش های پایگاه داده کاملاً خوب است، باید مراقب باشید تا مطمئن شوید که کار شما واقعاً می تواند با موفقیت اجرا شود. هنگام ارسال یک کار در یک تراکنش، ممکن است قبل از انجام معامله مادر، کار توسط کارگر پردازش شود. وقتی این اتفاق میافتد، ممکن است هر بهروزرسانی که در طول تراکنش(های) پایگاه داده در مدلها یا رکوردهای پایگاه داده انجام دادهاید، هنوز در پایگاه داده منعکس نشود. علاوه بر این، هر مدل یا رکورد پایگاه داده ایجاد شده در تراکنش(های) ممکن است در پایگاه داده وجود نداشته باشد.
Thankfully, Laravel provides several methods of working around this problem. First, you may set the
after_commit
connection option in your queue connection's configuration array:
'redis' => [ 'driver' => 'redis', // ... 'after_commit' => true,],
When the after_commit
option is true
, you may dispatch jobs within database transactions;
however, Laravel will wait until the open parent database transactions have been committed before actually
dispatching the job. Of course, if no database transactions are currently open, the job will be dispatched
immediately.
If a transaction is rolled back due to an exception that occurs during the transaction, the jobs that were dispatched during that transaction will be discarded.
Setting the
after_commit
configuration option totrue
will also cause any queued event listeners, mailables, notifications, and broadcast events to be dispatched after all open database transactions have been committed.
Specifying Commit Dispatch Behavior Inline
If you do not set the after_commit
queue connection configuration option to true
, you may
still indicate that a specific job should be dispatched after all open database transactions have been committed. To
accomplish this, you may chain the afterCommit
method onto your dispatch operation:
use App\Jobs\ProcessPodcast; ProcessPodcast::dispatch($podcast)->afterCommit();
Likewise, if the after_commit
configuration option is set to true
, you may indicate that a
specific job should be dispatched immediately without waiting for any open database transactions to commit:
ProcessPodcast::dispatch($podcast)->beforeCommit();
Job Chaining
Job chaining allows you to specify a list of queued jobs that should be run in sequence after the primary job has
executed successfully. If one job in the sequence fails, the rest of the jobs will not be run. To execute a queued
job chain, you may use the chain
method provided by the Bus
facade. Laravel's command bus
is a lower level component that queued job dispatching is built on top of:
use App\Jobs\OptimizePodcast;use App\Jobs\ProcessPodcast;use App\Jobs\ReleasePodcast;use Illuminate\Support\Facades\Bus; Bus::chain([ new ProcessPodcast, new OptimizePodcast, new ReleasePodcast,])->dispatch();
In addition to chaining job class instances, you may also chain closures:
Bus::chain([ new ProcessPodcast, new OptimizePodcast, function () { Podcast::update(/* ... */); },])->dispatch();
Deleting jobs using the
$this->delete()
method within the job will not prevent chained jobs from being processed. The chain will only stop executing if a job in the chain fails.
Chain Connection & Queue
If you would like to specify the connection and queue that should be used for the chained jobs, you may use the
onConnection
and onQueue
methods. These methods specify the queue connection and queue
name that should be used unless the queued job is explicitly assigned a different connection / queue:
Bus::chain([ new ProcessPodcast, new OptimizePodcast, new ReleasePodcast,])->onConnection('redis')->onQueue('podcasts')->dispatch();
Chain Failures
When chaining jobs, you may use the catch
method to specify a closure that should be invoked if a job
within the chain fails. The given callback will receive the Throwable
instance that caused the job
failure:
use Illuminate\Support\Facades\Bus;use Throwable; Bus::chain([ new ProcessPodcast, new OptimizePodcast, new ReleasePodcast,])->catch(function (Throwable $e) { // A job within the chain has failed...})->dispatch();
Since chain callbacks are serialized and executed at a later time by the Laravel queue, you should not use the
$this
variable within chain callbacks.
Customizing The Queue & Connection
Dispatching To A Particular Queue
با فشار دادن مشاغل به صف های مختلف، ممکن است مشاغل در صف خود را "دسته
بندی" کنید و حتی تعداد کارگرانی را که به صف های مختلف اختصاص می دهید، اولویت بندی کنید. به خاطر داشته باشید،
این کارها را به سمت "اتصالات" صف مختلف که توسط فایل پیکربندی صف شما تعریف شده است، سوق نمی دهد، بلکه فقط به
صف های خاص در یک اتصال واحد می رسد. برای تعیین صف،
onQueue
هنگام ارسال کار از روش استفاده کنید:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use App\Models\Podcast;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $podcast = Podcast::create(/* ... */); // Create podcast... ProcessPodcast::dispatch($podcast)->onQueue('processing'); }}
از طرف دیگر، میتوانید صف شغل را با فراخوانی
onQueue
متد در سازنده کار مشخص کنید:
<?php namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; class ProcessPodcast implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * Create a new job instance. * * @return void */ public function __construct() { $this->onQueue('processing'); }}
ارسال به یک اتصال خاص
اگر برنامه شما با چندین اتصال صف تعامل دارد، میتوانید با استفاده از
onConnection
روش مشخص کنید که کدام اتصال را به یک کار فشار دهید:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use App\Models\Podcast;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $podcast = Podcast::create(/* ... */); // Create podcast... ProcessPodcast::dispatch($podcast)->onConnection('sqs'); }}
میتوانید
برای تعیین اتصال و صف برای یک کار،
onConnection
و متدها را به هم متصل کنید:
onQueue
ProcessPodcast::dispatch($podcast) ->onConnection('sqs') ->onQueue('processing');
onConnection
همچنین، میتوانید با فراخوانی متد در سازنده کار،
اتصال کار را مشخص کنید :
<?php namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; class ProcessPodcast implements ShouldQueue{ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * Create a new job instance. * * @return void */ public function __construct() { $this->onConnection('sqs'); }}
تعیین حداکثر تلاشهای شغلی / مقادیر زمانبندی
حداکثر تلاش
اگر یکی از مشاغل در صف شما با خطا مواجه می شود، احتمالاً نمی خواهید آن را به طور نامحدود دوباره امتحان کنید. بنابراین، لاراول راه های مختلفی برای تعیین چند بار یا مدت زمان انجام یک کار ارائه می دهد.
یک روش برای تعیین حداکثر تعداد دفعاتی که ممکن است یک کار انجام شود، از
طریق
--tries
سوئیچ در خط فرمان Artisan است. این برای تمام کارهایی که کارگر پردازش
میکند اعمال میشود، مگر اینکه کار در حال پردازش تعداد دفعات انجام آن را مشخص کند:
php artisan queue:work --tries=3
اگر یک کار از حداکثر تعداد تلاش خود بیشتر شود، به عنوان یک کار "شکست
خورده" در نظر گرفته می شود. برای اطلاعات بیشتر در مورد رسیدگی به مشاغل ناموفق، به
مستندات شغلی ناموفق
مراجعه کنید . اگر
--tries=0
به دستور ارائه شود
queue:work
، کار به طور نامحدود دوباره امتحان می شود.
شما می توانید با تعیین حداکثر تعداد دفعاتی که ممکن است یک کار در خود طبقه
شغلی انجام شود، رویکرد دقیق تری داشته باشید. اگر حداکثر تعداد تلاش در کار مشخص شده باشد، بر مقدار
--tries
ارائه شده در خط فرمان ارجحیت خواهد داشت:
<?php namespace App\Jobs; class ProcessPodcast implements ShouldQueue{ /** * The number of times the job may be attempted. * * @var int */ public $tries = 5;}
تلاش های مبتنی بر زمان
بهعنوان جایگزینی برای تعریف چند بار انجام یک کار قبل از شکست، میتوانید
زمانی را تعریف کنید که در آن کار دیگر نباید تلاش کرد. این اجازه می دهد تا یک کار هر تعداد بار در یک بازه
زمانی مشخص انجام شود. برای تعیین زمانی که در آن کار دیگر نباید تلاش کرد، روشی را
retryUntil
به کلاس شغلی خود اضافه کنید. این متد باید یک
DateTime
نمونه
برگرداند :
/** * Determine the time at which the job should timeout. * * @return \DateTime */public function retryUntil(){ return now()->addMinutes(10);}
همچنین می توانید یک
tries
ویژگی یاretryUntil
متد را در شنوندگان رویداد در صف خود تعریف کنید .
حداکثر استثنائات
Sometimes you may wish to specify that a job may be attempted many times, but should fail if the retries are
triggered by a given number of unhandled exceptions (as opposed to being released by the release
method
directly). To accomplish this, you may define a maxExceptions
property on your job class:
<?php namespace App\Jobs; use Illuminate\Support\Facades\Redis; class ProcessPodcast implements ShouldQueue{ /** * The number of times the job may be attempted. * * @var int */ public $tries = 25; /** * The maximum number of unhandled exceptions to allow before failing. * * @var int */ public $maxExceptions = 3; /** * Execute the job. * * @return void */ public function handle() { Redis::throttle('key')->allow(10)->every(60)->then(function () { // Lock obtained, process the podcast... }, function () { // Unable to obtain lock... return $this->release(10); }); }}
In this example, the job is released for ten seconds if the application is unable to obtain a Redis lock and will continue to be retried up to 25 times. However, the job will fail if three unhandled exceptions are thrown by the job.
Timeout
The
pcntl
PHP extension must be installed in order to specify job timeouts.
Often, you know roughly how long you expect your queued jobs to take. For this reason, Laravel allows you to specify a "timeout" value. By default, the timeout value is 60 seconds. If a job is processing for longer than the number of seconds specified by the timeout value, the worker processing the job will exit with an error. Typically, the worker will be restarted automatically by a process manager configured on your server.
The maximum number of seconds that jobs can run may be specified using the --timeout
switch on the
Artisan command line:
php artisan queue:work --timeout=30
If the job exceeds its maximum attempts by continually timing out, it will be marked as failed.
You may also define the maximum number of seconds a job should be allowed to run on the job class itself. If the timeout is specified on the job, it will take precedence over any timeout specified on the command line:
<?php namespace App\Jobs; class ProcessPodcast implements ShouldQueue{ /** * The number of seconds the job can run before timing out. * * @var int */ public $timeout = 120;}
Sometimes, IO blocking processes such as sockets or outgoing HTTP connections may not respect your specified timeout. Therefore, when using these features, you should always attempt to specify a timeout using their APIs as well. For example, when using Guzzle, you should always specify a connection and request timeout value.
Failing On Timeout
If you would like to indicate that a job should be marked as failed on
timeout, you may define the $failOnTimeout
property on the job class:
/** * Indicate if the job should be marked as failed on timeout. * * @var bool */public $failOnTimeout = true;
Error Handling
If an exception is thrown while the job is being processed, the job will automatically be released back onto the
queue so it may be attempted again. The job will continue to be released until it has been attempted the maximum
number of times allowed by your application. The maximum number of attempts is defined by the --tries
switch used on the queue:work
Artisan command. Alternatively, the maximum number of attempts may be
defined on the job class itself. More information on running the queue worker can be found below.
Manually Releasing A Job
Sometimes you may wish to manually release a job back onto the queue so that it can be attempted again at a later
time. You may accomplish this by calling the release
method:
/** * Execute the job. * * @return void */public function handle(){ // ... $this->release();}
به طور پیشفرض، این
release
روش کار را برای پردازش فوری به صف باز میگرداند. با این حال، با ارسال یک
عدد صحیح به
release
متد، میتوانید به صف دستور دهید تا زمانی که تعداد معینی از ثانیه سپری
نشده است، کار را برای پردازش در دسترس قرار ندهد:
$this->release(10);
شکست دستی یک کار
گاهی اوقات ممکن است لازم باشد یک کار را به صورت دستی به عنوان "شکست
خورده" علامت گذاری کنید. برای انجام این کار، می توانید
fail
متد را فراخوانی کنید:
/** * Execute the job. * * @return void */public function handle(){ // ... $this->fail();}
اگر میخواهید شغل خود را بهعنوان ناموفق علامتگذاری کنید، به دلیل
استثنایی که پیدا کردهاید، میتوانید استثنا را به
fail
روش منتقل کنید. یا، برای راحتی، ممکن است یک پیام خطای رشته ای ارسال کنید
که برای شما به استثنا تبدیل می شود:
$this->fail($exception); $this->fail('Something went wrong.');
Job Batching
ویژگی Job Batching لاراول به شما این امکان را میدهد که به راحتی دستهای
از کارها را اجرا کنید و سپس زمانی که دستهای از کارها اجرا شدند، برخی اقدامات را انجام دهید. قبل از شروع،
باید یک انتقال پایگاه داده ایجاد کنید تا جدولی بسازید که حاوی اطلاعات متا در مورد دسته های شغلی شما، مانند
درصد تکمیل آنها باشد. این مهاجرت ممکن است با استفاده از دستور Artisan ایجاد شود
queue:batches-table
:
php artisan queue:batches-table php artisan migrate
تعریف مشاغل قابل دسته بندی
برای تعریف یک کار قابل دسته بندی، باید
یک کار در صف
به طور معمول ایجاد کنید. با این حال، شما باید این
Illuminate\Bus\Batchable
ویژگی را به کلاس شغلی اضافه کنید. این ویژگی دسترسی به
batch
روشی را فراهم می کند که ممکن است برای بازیابی دسته فعلی که کار در آن اجرا
می شود استفاده شود:
<?php namespace App\Jobs; use Illuminate\Bus\Batchable;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Foundation\Bus\Dispatchable;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Queue\SerializesModels; class ImportCsv implements ShouldQueue{ use Batchable, Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * Execute the job. * * @return void */ public function handle() { if ($this->batch()->cancelled()) { // Determine if the batch has been cancelled... return; } // Import a portion of the CSV file... }}
ارسال دسته ها
برای ارسال دسته ای از کارها باید از
batch
روش نما استفاده کنید
Bus
. البته، دسته بندی در درجه اول زمانی مفید است که با تماس های تکمیلی ترکیب
شود. بنابراین، میتوانید از روشهای
then
،
catch
و
finally
برای تعریف تماسهای تکمیلی برای دسته استفاده کنید. هر یک از این تماسها
Illuminate\Bus\Batch
در هنگام فراخوانی
یک نمونه دریافت میکنند .
در این مثال، تصور می کنیم که در صف دسته ای از کارها هستیم که هر کدام
تعداد مشخصی از ردیف ها را از یک فایل CSV پردازش می کنند:
use App\Jobs\ImportCsv;use Illuminate\Bus\Batch;use Illuminate\Support\Facades\Bus;use Throwable; $batch = Bus::batch([ new ImportCsv(1, 100), new ImportCsv(101, 200), new ImportCsv(201, 300), new ImportCsv(301, 400), new ImportCsv(401, 500),])->then(function (Batch $batch) { // All jobs completed successfully...})->catch(function (Batch $batch, Throwable $e) { // First batch job failure detected...})->finally(function (Batch $batch) { // The batch has finished executing...})->dispatch(); return $batch->id;
شناسه دسته، که ممکن است از طریق ویژگی قابل دسترسی باشد ، ممکن است برای
پرس و جو از گذرگاه فرمان لاراول
برای اطلاعات مربوط به دسته پس از ارسال
$batch->id
استفاده شود .
از آنجایی که کال بک های دسته ای سریالی می شوند و در زمان های بعدی توسط صف لاراول اجرا می شوند، نباید از
$this
متغیر درون callback ها استفاده کنید.
نام گذاری دسته ها
برخی از ابزارها مانند Laravel Horizon و Laravel Telescope ممکن است در
صورت نامگذاری دسته ها، اطلاعات رفع اشکال کاربرپسندتری را برای دسته ها ارائه دهند. برای اختصاص یک نام دلخواه
به یک دسته، می توانید
name
در هنگام تعریف دسته، متد را فراخوانی کنید:
$batch = Bus::batch([ // ...])->then(function (Batch $batch) { // All jobs completed successfully...})->name('Import CSV')->dispatch();
اتصال دسته ای و صف
اگر می خواهید اتصال و صفی را که باید برای کارهای دسته بندی شده استفاده
شود مشخص کنید، می توانید از روش
onConnection
و استفاده کنید
onQueue
. همه کارهای دستهای باید در یک اتصال و صف اجرا شوند:
$batch = Bus::batch([ // ...])->then(function (Batch $batch) { // All jobs completed successfully...})->onConnection('redis')->onQueue('imports')->dispatch();
زنجیر در دسته
شما می توانید با قرار دادن کارهای زنجیره ای در یک آرایه، مجموعه ای از کارهای زنجیره ای را در یک دسته تعریف کنید . به عنوان مثال، ممکن است دو زنجیره شغلی را به صورت موازی اجرا کنیم و زمانی که پردازش هر دو زنجیره کار به پایان رسید، یک callback اجرا کنیم:
use App\Jobs\ReleasePodcast;use App\Jobs\SendPodcastReleaseNotification;use Illuminate\Bus\Batch;use Illuminate\Support\Facades\Bus; Bus::batch([ [ new ReleasePodcast(1), new SendPodcastReleaseNotification(1), ], [ new ReleasePodcast(2), new SendPodcastReleaseNotification(2), ],])->then(function (Batch $batch) { // ...})->dispatch();
افزودن مشاغل به دسته ها
گاهی اوقات ممکن است اضافه کردن مشاغل اضافی به یک دسته از یک کار دستهای مفید باشد. این الگو زمانی میتواند مفید باشد که شما نیاز دارید هزاران شغل را دستهبندی کنید که ممکن است ارسال آنها در طول یک درخواست وب خیلی طول بکشد. بنابراین، در عوض، ممکن است بخواهید یک دسته اولیه از کارهای "لودر" را ارسال کنید که دسته را با کارهای بیشتر هیدراته می کند:
$batch = Bus::batch([ new LoadImportBatch, new LoadImportBatch, new LoadImportBatch,])->then(function (Batch $batch) { // All jobs completed successfully...})->name('Import Contacts')->dispatch();
در این مثال، ما از
LoadImportBatch
job برای هیدراته کردن دسته با کارهای اضافی استفاده خواهیم کرد. برای انجام
این کار، ممکن است از روشی در نمونه دسته ای استفاده کنیم
add
که ممکن است از طریق متد job قابل دسترسی باشد
batch
:
use App\Jobs\ImportContacts;use Illuminate\Support\Collection; /** * Execute the job. * * @return void */public function handle(){ if ($this->batch()->cancelled()) { return; } $this->batch()->add(Collection::times(1000, function () { return new ImportContacts; }));}
شما فقط می توانید از داخل شغلی که متعلق به همان دسته است، به یک دسته کار اضافه کنید.
بازرسی دسته ها
نمونهای
Illuminate\Bus\Batch
که برای تماسهای تکمیل دستهای ارائه میشود دارای ویژگیها و روشهای
مختلفی است که به شما در تعامل و بازرسی یک دسته معین از کارها کمک میکند:
// The UUID of the batch...$batch->id; // The name of the batch (if applicable)...$batch->name; // The number of jobs assigned to the batch...$batch->totalJobs; // The number of jobs that have not been processed by the queue...$batch->pendingJobs; // The number of jobs that have failed...$batch->failedJobs; // The number of jobs that have been processed thus far...$batch->processedJobs(); // The completion percentage of the batch (0-100)...$batch->progress(); // Indicates if the batch has finished executing...$batch->finished(); // Cancel the execution of the batch...$batch->cancel(); // Indicates if the batch has been cancelled...$batch->cancelled();
بازگرداندن دسته ها از مسیرها
همه
Illuminate\Bus\Batch
نمونهها قابل سریالسازی JSON هستند، به این معنی که میتوانید آنها را
مستقیماً از یکی از مسیرهای برنامه خود بازگردانید تا یک بار JSON حاوی اطلاعات مربوط به دسته، از جمله پیشرفت
تکمیل آن را بازیابی کنید. این باعث میشود اطلاعات مربوط به پیشرفت دسته در UI برنامه شما نمایش داده شود.
برای بازیابی یک دسته با شناسه آن، می توانید از روش
Bus
نما استفاده کنید
findBatch
:
use Illuminate\Support\Facades\Bus;use Illuminate\Support\Facades\Route; Route::get('/batch/{batchId}', function (string $batchId) { return Bus::findBatch($batchId);});
لغو دسته ها
گاهی اوقات ممکن است لازم باشد اجرای یک دسته معین را لغو کنید. این را می
توان با فراخوانی
cancel
متد در مثال زیر
انجام داد
Illuminate\Bus\Batch
:
/** * Execute the job. * * @return void */public function handle(){ if ($this->user->exceedsImportLimit()) { return $this->batch()->cancel(); } if ($this->batch()->cancelled()) { return; }}
همانطور که ممکن است در مثالهای قبلی متوجه شده باشید، کارهای دستهای
معمولاً باید تعیین کنند که آیا دسته مربوطه آنها قبل از ادامه اجرا لغو شده است یا خیر. با این حال، برای
راحتی، می توانید به جای آن
SkipIfBatchCancelled
میان افزار را
به کار اختصاص دهید. همانطور که از نام آن مشخص است، این میان افزار به
لاراول دستور می دهد که اگر دسته مربوط به آن لغو شد، کار را پردازش نکند:
use Illuminate\Queue\Middleware\SkipIfBatchCancelled; /** * Get the middleware the job should pass through. * * @return array */public function middleware(){ return [new SkipIfBatchCancelled];}
شکست دسته ای
هنگامی که یک کار دستهای با شکست مواجه میشود،
catch
پاسخ تماس (در صورت اختصاص داده شده) فراخوانی میشود. این فراخوانی فقط
برای اولین کاری که در دسته با شکست مواجه می شود فراخوانی می شود.
اجازه دادن به شکست ها
هنگامی که یک کار در یک دسته با شکست مواجه می شود، لاراول به طور خودکار
دسته را به عنوان "لغو" علامت گذاری می کند. در صورت تمایل، می توانید این رفتار را غیرفعال کنید تا یک شکست
شغلی به طور خودکار دسته را به عنوان لغو علامت گذاری نکند. این ممکن است با فراخوانی
allowFailures
متد در حین ارسال دسته انجام شود:
$batch = Bus::batch([ // ...])->then(function (Batch $batch) { // All jobs completed successfully...})->allowFailures()->dispatch();
تلاش مجدد برای کارهای دسته ای ناموفق
برای راحتی کار، لاراول
queue:retry-batch
دستور Artisan را ارائه می دهد که به شما امکان می دهد به راحتی تمام کارهای
ناموفق را برای یک دسته مشخص دوباره امتحان کنید. دستور
queue:retry-batch
UUID دستهای را میپذیرد که کارهای ناموفق آن باید دوباره امتحان شوند:
php artisan queue:retry-batch 32dbc76c-4f82-4749-b610-a639fe0099b5
دسته های هرس
بدون هرس،
job_batches
جدول می تواند رکوردها را خیلی سریع جمع آوری کند. برای کاهش این مشکل، باید
دستور
Artisan را برای اجرای روزانه
برنامه ریزی کنید :
queue:prune-batches
$schedule->command('queue:prune-batches')->daily();
به طور پیش فرض، تمام دسته های تمام شده که بیش از 24 ساعت از عمر آنها می
گذرد، هرس می شوند. می توانید
hours
هنگام فراخوانی فرمان از این گزینه برای تعیین مدت زمان نگهداری داده های
دسته ای استفاده کنید. به عنوان مثال، دستور زیر تمام دسته هایی را که بیش از 48 ساعت قبل تمام شده اند حذف می
کند:
$schedule->command('queue:prune-batches --hours=48')->daily();
گاهی اوقات، جدول شما
jobs_batches
ممکن است سوابق دستهای را برای دستههایی که هرگز با موفقیت تکمیل
نشدهاند، جمعآوری کند، مانند دستههایی که یک کار شکست خورده و آن کار هرگز با موفقیت دوباره امتحان نشده است.
میتوانید
queue:prune-batches
با استفاده از این گزینه دستور هرس کردن این رکوردهای دستهای ناتمام را
بدهید
unfinished
:
$schedule->command('queue:prune-batches --hours=48 --unfinished=72')->daily();
به همین ترتیب، جدول شما
jobs_batches
همچنین ممکن است سوابق دسته ای را برای دسته های لغو شده جمع آوری کند.
میتوانید
queue:prune-batches
با استفاده از این گزینه دستور هرس کردن این رکوردهای دستهای لغو شده را
بدهید
cancelled
:
$schedule->command('queue:prune-batches --hours=48 --cancelled=72')->daily();
بسته شدن صف
به جای اعزام یک کلاس شغلی به صف، ممکن است یک تعطیلی نیز ارسال کنید. این برای کارهای سریع و ساده که باید خارج از چرخه درخواست فعلی اجرا شوند عالی است. هنگام ارسال بستهها به صف، محتوای کد بستهبندی بهصورت رمزنگاری امضا میشود تا در حین انتقال قابل تغییر نباشد:
$podcast = App\Podcast::find(1); dispatch(function () use ($podcast) { $podcast->publish();});
با استفاده از این
catch
روش، میتوانید بستهای را ارائه دهید که اگر بسته شدن در صف پس از اتمام
تمام
تلاشهای مجدد پیکربندی شده
صف شما با موفقیت کامل نشد، باید اجرا شود :
use Throwable; dispatch(function () use ($podcast) { $podcast->publish();})->catch(function (Throwable $e) { // This job has failed...});
از آنجایی که
catch
کال بک ها سریالی می شوند و در زمان های بعدی توسط صف لاراول اجرا می شوند، نباید از$this
متغیر درونcatch
callback ها استفاده کنید.
اجرای The Queue Worker
دستور
queue:work
_
لاراول شامل یک دستور Artisan است که یک queue worker را راه اندازی می کند
و کارهای جدید را همانطور که در صف قرار می دهند پردازش می کند. شما می توانید کارگر را با استفاده از
queue:work
دستور Artisan اجرا کنید. توجه داشته باشید که پس از
queue:work
شروع فرمان، تا زمانی که به صورت دستی متوقف شود یا ترمینال خود را ببندید،
به اجرا ادامه خواهد داد:
php artisan queue:work
برای اینکه
queue:work
فرآیند بهطور دائم در پسزمینه اجرا شود، باید از یک مانیتور فرآیند مانند Supervisor استفاده کنید تا مطمئن شوید که کارفرمای صف متوقف نمیشود.
اگر میخواهید شناسههای شغلی پردازششده در خروجی فرمان گنجانده شوند،
میتوانید
-v
هنگام فراخوانی دستور، پرچم را اضافه کنید:
queue:work
php artisan queue:work -v
Remember, queue workers are long-lived processes and store the booted application state in memory. As a result, they will not notice changes in your code base after they have been started. So, during your deployment process, be sure to restart your queue workers. In addition, remember that any static state created or modified by your application will not be automatically reset between jobs.
Alternatively, you may run the queue:listen
command. When using the queue:listen
command,
you don't have to manually restart the worker when you want to reload your updated code or reset the application
state; however, this command is significantly less efficient than the queue:work
command:
php artisan queue:listen
Running Multiple Queue Workers
To assign multiple workers to a queue and process jobs concurrently, you should simply start multiple
queue:work
processes. This can either be done locally via multiple tabs in your terminal or in
production using your process manager's configuration settings. When using
Supervisor, you may use the numprocs
configuration value.
Specifying The Connection & Queue
You may also specify which queue connection the worker should utilize. The connection name passed to the
work
command should correspond to one of the connections defined in your config/queue.php
configuration file:
php artisan queue:work redis
By default, the queue:work
command only processes jobs for the default queue on a given connection.
However, you may customize your queue worker even further by only processing particular queues for a given
connection. For example, if all of your emails are processed in an emails
queue on your
redis
queue connection, you may issue the following command to start a worker that only processes that
queue:
php artisan queue:work redis --queue=emails
Processing A Specified Number Of Jobs
The --once
option may be used to instruct the worker to only process a single job from the queue:
php artisan queue:work --once
The --max-jobs
option may be used to instruct the worker to process the given number of jobs and then
exit. This option may be useful when combined with Supervisor so that your
workers are automatically restarted after processing a given number of jobs, releasing any memory they may have
accumulated:
php artisan queue:work --max-jobs=1000
Processing All Queued Jobs & Then Exiting
The --stop-when-empty
option may be used to instruct the worker to process all jobs and then exit
gracefully. This option can be useful when processing Laravel queues within a Docker container if you wish to
shutdown the container after the queue is empty:
php artisan queue:work --stop-when-empty
Processing Jobs For A Given Number Of Seconds
The --max-time
option may be used to instruct the worker to process jobs for the given number of seconds
and then exit. This option may be useful when combined with Supervisor so
that your workers are automatically restarted after processing jobs for a given amount of time, releasing any memory
they may have accumulated:
# Process jobs for one hour and then exit...php artisan queue:work --max-time=3600
Worker Sleep Duration
When jobs are available on the queue, the worker will keep processing jobs with no delay in between jobs. However,
the sleep
option determines how many seconds the worker will "sleep" if there are no jobs available. Of
course, while sleeping, the worker will not process any new jobs:
php artisan queue:work --sleep=3
Resource Considerations
Daemon queue workers do not "reboot" the framework before processing each job. Therefore, you should release any
heavy resources after each job completes. For example, if you are doing image manipulation with the GD library, you
should free the memory with imagedestroy
when you are done processing the image.
Queue Priorities
Sometimes you may wish to prioritize how your queues are processed. For example, in your
config/queue.php
configuration file, you may set the default queue
for your
redis
connection to low
. However, occasionally you may wish to push a job to a
high
priority queue like so:
dispatch((new Job)->onQueue('high'));
To start a worker that verifies that all of the high
queue jobs are processed before continuing to any
jobs on the low
queue, pass a comma-delimited list of queue names to the work
command:
php artisan queue:work --queue=high,low
Queue Workers & Deployment
Since queue workers are long-lived processes, they will not notice changes to your code without being restarted. So,
the simplest way to deploy an application using queue workers is to restart the workers during your deployment
process. You may gracefully restart all of the workers by issuing the queue:restart
command:
php artisan queue:restart
This command will instruct all queue workers to gracefully exit after they finish processing their current job so
that no existing jobs are lost. Since the queue workers will exit when the queue:restart
command is
executed, you should be running a process manager such as Supervisor to
automatically restart the queue workers.
The queue uses the cache to store restart signals, so you should verify that a cache driver is properly configured for your application before using this feature.
Job Expirations & Timeouts
Job Expiration
در فایل پیکربندی شما
config/queue.php
، هر اتصال صف یک
retry_after
گزینه را تعریف می کند. این گزینه مشخص می کند که اتصال صف باید چند ثانیه
منتظر بماند تا کاری که در حال پردازش است دوباره امتحان شود. به عنوان مثال، اگر مقدار روی
retry_after
تنظیم شود
90
، اگر کار به مدت 90 ثانیه بدون آزاد شدن یا حذف شدن پردازش شده باشد،
دوباره در صف قرار می گیرد. به طور معمول، شما باید
retry_after
مقدار را روی حداکثر تعداد ثانیه هایی که کار شما به طور منطقی باید طول
بکشد تا پردازش کامل شود، تنظیم کنید.
تنها اتصال صفی که حاوی مقدار نیست
retry_after
Amazon SQS است. SQS کار را بر اساس پیشفرض زمان نمایان بودن که در کنسول AWS مدیریت میشود، دوباره امتحان میکند.
تایم اوت های کارگری
دستور
queue:work
Artisan یک
--timeout
گزینه را آشکار می کند. به طور پیش فرض،
--timeout
مقدار 60 ثانیه است. اگر یک کار بیش از تعداد ثانیه های مشخص شده توسط مقدار
زمان وقفه در حال پردازش باشد، کارگری که کار را پردازش می کند با خطا خارج می شود. به طور معمول، worker به طور
خودکار توسط
مدیر فرآیند پیکربندی شده روی سرور شما
راه اندازی مجدد می شود :
php artisan queue:work --timeout=60
گزینه پیکربندی
retry_after
و
--timeout
گزینه CLI متفاوت هستند، اما با هم کار می کنند تا اطمینان حاصل شود که
مشاغل از بین نمی روند و کارها فقط یک بار با موفقیت پردازش می شوند.
مقدار
--timeout
باید همیشه حداقل چند ثانیه کوتاهتر ازretry_after
مقدار پیکربندی شما باشد. این تضمین می کند که کارگری که یک کار منجمد شده را پردازش می کند همیشه قبل از امتحان مجدد کار خاتمه می یابد. اگر--timeout
گزینه شما بیشتر ازretry_after
مقدار پیکربندی شما باشد، ممکن است کارهای شما دو بار پردازش شود.
پیکربندی سرپرست
در تولید، شما به راهی نیاز دارید که
queue:work
فرآیندهای خود را در حال اجرا نگه دارید. ممکن است
یک
queue:work
فرآیند به دلایل مختلفی از جمله مهلت زمانی بیش از حد کارگر یا اجرای فرمان
متوقف شود
queue:restart
.
به همین دلیل، باید یک مانیتور فرآیند را پیکربندی کنید که بتواند زمان
queue:work
خروج فرآیندهای شما را تشخیص دهد و به طور خودکار آنها را راه اندازی مجدد
کند. علاوه بر این، مانیتورهای فرآیند می توانند به شما این امکان را بدهند که تعیین کنید چند
queue:work
فرآیند را می خواهید همزمان اجرا کنید. Supervisor یک مانیتور فرآیند است که
معمولاً در محیطهای لینوکس استفاده میشود و نحوه پیکربندی آن را در مستندات زیر توضیح خواهیم داد.
نصب سوپروایزر
Supervisor یک مانیتور فرآیند برای سیستم عامل لینوکس است و
queue:work
در صورت عدم موفقیت فرآیندهای شما را به طور خودکار راه اندازی مجدد می کند.
برای نصب Supervisor در اوبونتو، می توانید از دستور زیر استفاده کنید:
sudo apt-get install supervisor
اگر پیکربندی و مدیریت Supervisor به نظر سخت می رسد، از Laravel Forge استفاده کنید ، که به طور خودکار Supervisor را برای پروژه های Laravel تولیدی شما نصب و پیکربندی می کند.
پیکربندی سرپرست
فایل های پیکربندی ناظر معمولاً در
/etc/supervisor/conf.d
دایرکتوری ذخیره می شوند. در این فهرست، میتوانید هر تعداد فایل پیکربندی
ایجاد کنید که به سرپرست آموزش میدهد که چگونه فرآیندهای شما باید نظارت شوند. به عنوان مثال، بیایید یک
laravel-worker.conf
فایل ایجاد کنیم که
queue:work
فرآیندها را شروع و نظارت کند:
[program:laravel-worker]process_name=%(program_name)s_%(process_num)02dcommand=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3 --max-time=3600autostart=trueautorestart=truestopasgroup=truekillasgroup=trueuser=forgenumprocs=8redirect_stderr=truestdout_logfile=/home/forge/app.com/worker.logstopwaitsecs=3600
در این مثال،
numprocs
دستورالعمل به Supervisor دستور می دهد تا هشت
queue:work
فرآیند را اجرا کند و همه آنها را نظارت کند و در صورت شکست، به طور خودکار
آنها را مجدداً راه اندازی کند. شما باید
command
دستورالعمل پیکربندی را تغییر دهید تا اتصال صف مورد نظر و گزینه های کارگر
را منعکس کند.
باید اطمینان حاصل کنید که ارزش آن
stopwaitsecs
از تعداد ثانیه های مصرف شده توسط طولانی ترین کار شما بیشتر است. در غیر این صورت، Supervisor ممکن است کار را قبل از اتمام پردازش آن از بین ببرد.
راه اندازی سرپرست
پس از ایجاد فایل پیکربندی، میتوانید پیکربندی Supervisor را بهروزرسانی کنید و فرآیندها را با استفاده از دستورات زیر شروع کنید:
sudo supervisorctl reread sudo supervisorctl update sudo supervisorctl start laravel-worker:*
برای اطلاعات بیشتر در مورد Supervisor، به مستندات Supervisor مراجعه کنید .
مقابله با مشاغل ناموفق
گاهی اوقات مشاغل در صف شما با شکست مواجه می شوند. نگران نباشید، همه چیز
همیشه طبق برنامه پیش نمی رود! لاراول شامل یک راه راحت برای
تعیین حداکثر تعداد دفعاتی است که یک کار باید انجام شود
. پس از اینکه یک کار ناهمزمان از این تعداد تلاش بیشتر شد، در جدول پایگاه
داده درج می شود
failed_jobs
.
کارهای ارسالی همزمان
که با شکست مواجه می شوند در این جدول ذخیره نمی شوند و استثناهای آنها
بلافاصله توسط برنامه مدیریت می شود.
مهاجرت برای ایجاد
failed_jobs
جدول معمولاً در برنامه های جدید لاراول وجود دارد. با این حال، اگر برنامه
شما حاوی یک انتقال برای این جدول نیست، می توانید از
queue:failed-table
دستور برای ایجاد مهاجرت استفاده کنید:
php artisan queue:failed-table php artisan migrate
هنگام اجرای یک فرآیند
queue worker
، میتوانید حداکثر تعداد دفعاتی که یک کار باید با استفاده از
--tries
سوئیچ روی
queue:work
دستور انجام شود را مشخص کنید. اگر مقداری را برای گزینه مشخص نکنید
--tries
، jobها فقط یک بار یا به تعداد مشخص شده توسط
$tries
ویژگی کلاس شغلی انجام خواهند شد:
php artisan queue:work redis --tries=3
با استفاده از این
--backoff
گزینه، میتوانید مشخص کنید که لاراول چند ثانیه قبل از امتحان مجدد کاری که
با استثنا مواجه شده است، صبر کند. بهطور پیشفرض، یک کار فوراً به صف باز میگردد تا دوباره تلاش شود:
php artisan queue:work redis --tries=3 --backoff=3
اگر می خواهید تنظیم کنید که لاراول چند ثانیه باید قبل از امتحان مجدد کاری
که بر اساس هر شغل با استثنا مواجه شده است، منتظر بماند، می توانید این کار را با تعریف یک
backoff
ویژگی در کلاس شغلی خود انجام دهید:
/** * The number of seconds to wait before retrying the job. * * @var int */public $backoff = 3;
اگر به منطق پیچیده تری برای تعیین زمان عقب نشینی شغل نیاز دارید، می
توانید روشی را
backoff
در کلاس شغلی خود تعریف کنید:
/*** Calculate the number of seconds to wait before retrying the job.** @return int*/public function backoff(){ return 3;}
شما می توانید به راحتی با برگرداندن آرایه ای از مقادیر backoff از
backoff
متد، پشتیبان های "نمایی" را پیکربندی کنید. در این مثال، تأخیر در تلاش
مجدد 1 ثانیه برای اولین بار، 5 ثانیه برای تلاش مجدد دوم و 10 ثانیه برای تلاش مجدد سوم خواهد بود:
/*** Calculate the number of seconds to wait before retrying the job.** @return array*/public function backoff(){ return [1, 5, 10];}
تمیز کردن پس از انجام کارهای ناموفق
هنگامی که یک کار خاص با شکست مواجه می شود، ممکن است بخواهید یک هشدار برای
کاربران خود ارسال کنید یا هر اقدامی را که تا حدی توسط کار انجام شده است، برگردانید. برای انجام این کار، ممکن
است
failed
روشی را در کلاس شغلی خود تعریف کنید. نمونه
ای
Throwable
که باعث شکست کار شده است به
failed
متد ارسال می شود:
<?php namespace App\Jobs; use App\Models\Podcast;use App\Services\AudioProcessor;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Queue\SerializesModels;use Throwable; class ProcessPodcast implements ShouldQueue{ use InteractsWithQueue, Queueable, SerializesModels; /** * The podcast instance. * * @var \App\Podcast */ public $podcast; /** * Create a new job instance. * * @param \App\Models\Podcast $podcast * @return void */ public function __construct(Podcast $podcast) { $this->podcast = $podcast; } /** * Execute the job. * * @param \App\Services\AudioProcessor $processor * @return void */ public function handle(AudioProcessor $processor) { // Process uploaded podcast... } /** * Handle a job failure. * * @param \Throwable $exception * @return void */ public function failed(Throwable $exception) { // Send user notification of failure, etc... }}
یک نمونه جدید از کار قبل از فراخوانی
failed
روش نمونه سازی می شود. بنابراین، هر گونه تغییر ویژگی کلاس که ممکن است درhandle
متد رخ داده باشد از بین خواهد رفت.
تلاش مجدد مشاغل ناموفق
برای مشاهده تمام کارهای ناموفق که در
failed_jobs
جدول پایگاه داده شما درج شده اند، می توانید از
queue:failed
دستور Artisan استفاده کنید:
php artisan queue:failed
این
queue:failed
فرمان شناسه شغل، اتصال، صف، زمان شکست و سایر اطلاعات مربوط به کار را
فهرست می کند. شناسه شغل ممکن است برای امتحان مجدد کار ناموفق استفاده شود. به عنوان مثال، برای امتحان مجدد یک
کار ناموفق که دارای شناسه است
ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece
، دستور زیر را صادر کنید:
php artisan queue:retry ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece
در صورت لزوم، می توانید چندین شناسه را به دستور ارسال کنید:
php artisan queue:retry ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece 91401d2c-0784-4f43-824c-34f94a33c24d
همچنین میتوانید همه کارهای ناموفق را برای یک صف خاص دوباره امتحان کنید:
php artisan queue:retry --queue=name
برای امتحان مجدد همه کارهای ناموفق خود،
queue:retry
دستور را اجرا کرده و
all
به عنوان شناسه ارسال کنید:
php artisan queue:retry all
اگر می خواهید یک کار ناموفق را حذف کنید، می توانید از
queue:forget
دستور زیر استفاده کنید:
php artisan queue:forget 91401d2c-0784-4f43-824c-34f94a33c24d
هنگام استفاده از Horizon ، باید از
horizon:forget
دستور حذف یک کار ناموفق به جایqueue:forget
دستور استفاده کنید.
برای حذف تمام کارهای ناموفق خود از
failed_jobs
جدول، می توانید از
queue:flush
دستور زیر استفاده کنید:
php artisan queue:flush
نادیده گرفتن مدل های گمشده
هنگام تزریق یک مدل Eloquent به یک کار، مدل قبل از قرار گرفتن در صف به طور
خودکار سریال سازی می شود و در هنگام پردازش کار دوباره از پایگاه داده بازیابی می شود. با این حال، اگر در
زمانی که کار در انتظار پردازش توسط کارگر بود، مدل حذف شده باشد، ممکن است کار شما با یک علامت شکست بخورد
ModelNotFoundException
.
برای راحتی کار، میتوانید با تنظیم
deleteWhenMissingModels
ویژگی شغل خود به صورت خودکار، کارهای دارای مدلهای گمشده را حذف کنید
true
. هنگامی که این ویژگی روی تنظیم شود
true
، لاراول بی سر و صدا کار را بدون ذکر استثنا کنار می گذارد:
/** * Delete the job if its models no longer exist. * * @var bool */public $deleteWhenMissingModels = true;
هرس مشاغل ناموفق
می توانید رکوردهای
failed_jobs
جدول برنامه خود را با فراخوانی
queue:prune-failed
دستور Artisan هرس کنید:
php artisan queue:prune-failed
به طور پیش فرض، تمام سوابق شغلی ناموفق که بیش از 24 ساعت از آن می گذرد،
هرس می شوند. اگر این گزینه را برای فرمان ارائه دهید
--hours
، فقط سوابق شغلی ناموفق که در N ساعت گذشته درج شده اند، حفظ خواهند شد. به
عنوان مثال، دستور زیر تمام سوابق شغلی ناموفق را که بیش از 48 ساعت قبل درج شده اند حذف می کند:
php artisan queue:prune-failed --hours=48
ذخیره مشاغل ناموفق در DynamoDB
لاراول همچنین از ذخیره سوابق شغلی ناموفق شما در
DynamoDB
به جای جدول پایگاه داده رابطه ای پشتیبانی می کند. با این حال، شما باید
یک جدول DynamoDB ایجاد کنید تا تمام رکوردهای کار ناموفق را ذخیره کنید. به طور معمول، این جدول باید نامگذاری
شود
failed_jobs
، اما شما باید جدول را بر اساس مقدار مقدار
queue.failed.table
پیکربندی در فایل پیکربندی برنامه خود نامگذاری کنید
queue
.
جدول
failed_jobs
باید دارای یک کلید پارتیشن اصلی رشته ای به نام
application
و یک کلید مرتب سازی اولیه رشته به نام باشد
uuid
. بخشی
application
از کلید شامل نام برنامه شما خواهد بود که توسط
name
مقدار پیکربندی در فایل پیکربندی برنامه شما تعریف شده است
app
. از آنجایی که نام برنامه بخشی از کلید جدول DynamoDB است، می توانید از
همان جدول برای ذخیره کارهای ناموفق برای چندین برنامه لاراول استفاده کنید.
علاوه بر این، اطمینان حاصل کنید که AWS SDK را نصب کرده اید تا برنامه لاراول شما بتواند با آمازون DynamoDB ارتباط برقرار کند:
composer require aws/aws-sdk-php
در مرحله بعد،
queue.failed.driver
مقدار گزینه پیکربندی را روی
dynamodb
. علاوه بر این، باید گزینه های پیکربندی
key
،
secret
و
region
پیکربندی را در آرایه پیکربندی کار ناموفق تعریف کنید. این گزینه ها برای
احراز هویت با AWS استفاده خواهند شد. هنگام استفاده از
dynamodb
درایور،
queue.failed.database
گزینه پیکربندی غیر ضروری است:
'failed' => [ 'driver' => env('QUEUE_FAILED_DRIVER', 'dynamodb'), 'key' => env('AWS_ACCESS_KEY_ID'), 'secret' => env('AWS_SECRET_ACCESS_KEY'), 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 'table' => 'failed_jobs',],
غیرفعال کردن ذخیرهسازی کار ناموفق
شما می توانید با تنظیم
queue.failed.driver
مقدار گزینه پیکربندی روی
null
. به طور معمول، این ممکن است از طریق
QUEUE_FAILED_DRIVER
متغیر محیطی انجام شود:
QUEUE_FAILED_DRIVER=null
رویدادهای شغلی ناموفق
اگر می خواهید شنونده رویدادی را ثبت کنید که در صورت شکست کاری فراخوانی می
شود، می توانید از روش
Queue
نما استفاده کنید
failing
. به عنوان مثال، ممکن است از
boot
روشی
AppServiceProvider
که در لاراول گنجانده شده است،
یک بسته به این رویداد اضافه کنیم :
<?php namespace App\Providers; use Illuminate\Support\Facades\Queue;use Illuminate\Support\ServiceProvider;use Illuminate\Queue\Events\JobFailed; class AppServiceProvider extends ServiceProvider{ /** * Register any application services. * * @return void */ public function register() { // } /** * Bootstrap any application services. * * @return void */ public function boot() { Queue::failing(function (JobFailed $event) { // $event->connectionName // $event->job // $event->exception }); }}
پاک کردن مشاغل از صف
هنگام استفاده از Horizon ، باید
horizon:clear
به جای دستور، از دستور پاک کردن مشاغل از صف استفاده کنیدqueue:clear
.
اگر میخواهید همه کارها را از صف پیشفرض اتصال پیشفرض حذف کنید،
میتوانید با استفاده از
queue:clear
دستور Artisan این کار را انجام دهید:
php artisan queue:clear
همچنین میتوانید
connection
آرگومان و
queue
گزینهای برای حذف کارها از یک اتصال و صف خاص ارائه دهید:
php artisan queue:clear redis --queue=emails
پاک کردن کارها از صف ها فقط برای درایورهای صف SQS، Redis و پایگاه داده در دسترس است. علاوه بر این، فرآیند حذف پیام SQS تا 60 ثانیه طول می کشد، بنابراین کارهای ارسال شده به صف SQS تا 60 ثانیه پس از پاک کردن صف نیز ممکن است حذف شوند.
نظارت بر صف های شما
اگر صف شما هجوم ناگهانی کارها را دریافت کند، ممکن است غرق شود و منجر به انتظار طولانی برای تکمیل کارها شود. در صورت تمایل، لاراول می تواند به شما هشدار دهد که تعداد کارهای صف شما از آستانه مشخص شده فراتر رود.
برای شروع، باید
queue:monitor
دستور را برای
اجرای هر دقیقه
برنامه ریزی کنید . این دستور نام صف هایی را که می خواهید نظارت کنید و
همچنین آستانه تعداد کار مورد نظر شما را می پذیرد:
php artisan queue:monitor redis:default,redis:deployments --max=100
زمانبندی این دستور به تنهایی برای راهاندازی یک اعلان که وضعیت بیش از حد
صف را به شما هشدار میدهد کافی نیست. هنگامی که دستور با صفی مواجه می شود که تعداد کار از آستانه شما بیشتر
است، یک
Illuminate\Queue\Events\QueueBusy
رویداد ارسال می شود. میتوانید به این رویداد در برنامهتان گوش دهید
EventServiceProvider
تا یک اعلان برای شما یا تیم توسعهتان ارسال شود:
use App\Notifications\QueueHasLongWaitTime;use Illuminate\Queue\Events\QueueBusy;use Illuminate\Support\Facades\Event;use Illuminate\Support\Facades\Notification; /** * Register any other events for your application. * * @return void */public function boot(){ Event::listen(function (QueueBusy $event) { Notification::route('mail', 'dev@example.com') ->notify(new QueueHasLongWaitTime( $event->connection, $event->queue, $event->size )); });}
رویدادهای شغلی
با استفاده از
before
و
after
متدهای روی
Queue
نما
، میتوانید فراخوانهایی را مشخص کنید که قبل یا بعد از پردازش یک کار در
صف اجرا شوند. این فراخوان ها فرصتی عالی برای انجام ثبت گزارش یا آمار افزایشی برای داشبورد هستند. به طور
معمول، شما باید این روش ها را از
boot
روش
ارائه دهنده خدمات
فراخوانی کنید . به عنوان مثال، ممکن است از چیزی
AppServiceProvider
که در لاراول موجود است
استفاده کنیم :
<?php namespace App\Providers; use Illuminate\Support\Facades\Queue;use Illuminate\Support\ServiceProvider;use Illuminate\Queue\Events\JobProcessed;use Illuminate\Queue\Events\JobProcessing; class AppServiceProvider extends ServiceProvider{ /** * Register any application services. * * @return void */ public function register() { // } /** * Bootstrap any application services. * * @return void */ public function boot() { Queue::before(function (JobProcessing $event) { // $event->connectionName // $event->job // $event->job->payload() }); Queue::after(function (JobProcessed $event) { // $event->connectionName // $event->job // $event->job->payload() }); }}
با استفاده از
looping
روش روی
Queue
نما
، میتوانید فراخوانهایی را مشخص کنید که قبل از تلاش کارگر برای واکشی
کاری از یک صف اجرا شوند. به عنوان مثال، ممکن است برای بازگرداندن تراکنشهایی که توسط یک کار شکست خورده قبلی
باز مانده بودند، بسته شدن را ثبت کنید:
use Illuminate\Support\Facades\DB;use Illuminate\Support\Facades\Queue; Queue::looping(function () { while (DB::transactionLevel() > 0) { DB::rollBack(); }});