صف ها
- معرفی
- ایجاد اشتغال
- میان افزار شغلی
- اعزام مشاغل
- Job Batching
- بسته شدن صف
- اجرای صف کارگر
- پیکربندی سرپرست
- مقابله با مشاغل ناموفق
- پاک کردن مشاغل از صف
- نظارت بر صف های شما
- آزمایش کردن
- رویدادهای شغلی
معرفی
در حین ساختن برنامه وب خود، ممکن است وظایفی داشته باشید، مانند تجزیه و ذخیره یک فایل 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
درایور صف، به یک جدول پایگاه داده برای نگهداری کارها نیاز دارید. به طور معمول، این در
0001_01_01_000002_create_jobs_table.php
انتقال پایگاه داده
پیش فرض لاراول گنجانده شده است
. با این حال، اگر برنامه شما حاوی این مهاجرت نیست، می توانید از
make:queue-table
دستور Artisan برای ایجاد آن استفاده کنید:
php artisan make:queue-table php artisan migrate
ردیس
برای استفاده از
redis
درایور صف، باید یک اتصال پایگاه داده Redis را در
config/database.php
فایل پیکربندی خود پیکربندی کنید.
گزینه های
serializer
وcompression
Redis توسط درایور صف پشتیبانی نمی شوندredis
.
خوشه ردیس
اگر اتصال صف Redis شما از یک Redis Cluster استفاده میکند، نامهای صف شما باید حاوی تگ هش کلید باشند . این برای اطمینان از اینکه همه کلیدهای Redis برای یک صف معین در یک شکاف هش قرار میگیرند، لازم است:
'redis' => [ 'driver' => 'redis', 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), 'queue' => env('REDIS_QUEUE', '{default}'), 'retry_after' => env('REDIS_QUEUE_RETRY_AFTER', 90), 'block_for' => null, 'after_commit' => false,],
مسدود کردن
هنگام استفاده از صف Redis، میتوانید از
block_for
گزینه پیکربندی استفاده کنید تا مشخص کنید راننده چه مدت باید منتظر بماند تا یک کار قبل از تکرار از طریق حلقه کارگر و نظرسنجی مجدد پایگاه داده Redis باشد.
تنظیم این مقدار بر اساس بار صف می تواند کارآمدتر از نظرسنجی مداوم پایگاه داده Redis برای کارهای جدید باشد. به عنوان مثال، می توانید مقدار را
5
برای نشان دادن اینکه درایور باید برای پنج ثانیه مسدود شود در حالی که منتظر در دسترس قرار گرفتن یک کار است، تنظیم کنید:
'redis' => [ 'driver' => 'redis', 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), 'queue' => env('REDIS_QUEUE', 'default'), 'retry_after' => env('REDIS_QUEUE_RETRY_AFTER', 90), 'block_for' => 5, 'after_commit' => false,],
تنظیم
block_for
روی0
باعث میشود تا کارگران صف بهطور نامحدود مسدود شوند تا زمانی که کار در دسترس باشد. این همچنین از کنترل سیگنالهایی مانندSIGTERM
تا پردازش کار بعدی جلوگیری میکند.
سایر پیش نیازهای راننده
وابستگی های زیر برای درایورهای صف فهرست شده مورد نیاز است. این وابستگی ها ممکن است از طریق مدیر بسته Composer نصب شوند:
-
آمازون SQS:
aws/aws-sdk-php ~3.0
-
Beanstalkd:
pda/pheanstalk ~5.0
-
Redis:
predis/predis ~2.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; /** * Create a new job instance. */ public function __construct( public Podcast $podcast, ) {} /** * Execute the job. */ public function handle(AudioProcessor $processor): void { // 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;use Illuminate\Contracts\Foundation\Application; $this->app->bindMethod([ProcessPodcast::class, 'handle'], function (ProcessPodcast $job, Application $app) { return $job->handle($app->make(AudioProcessor::class));});
داده های باینری، مانند محتویات تصویر خام، باید
base64_encode
قبل از ارسال به یک کار در صف، از طریق تابع ارسال شوند. در غیر این صورت، کار ممکن است به درستی به JSON تبدیل نشود، زمانی که در صف قرار میگیرد.
روابط در صف
از آنجایی که همه روابط مدل Eloquent بارگذاری شده، زمانی که یک کار در صف قرار میگیرد، سریال میشوند، رشته شغلی سریالشده گاهی اوقات میتواند بسیار بزرگ شود. علاوه بر این، هنگامی که یک کار از حالت سریال خارج می شود و روابط مدل مجدداً از پایگاه داده بازیابی می شوند، به طور کامل بازیابی می شوند. هر گونه محدودیت رابطه قبلی که قبل از سریال سازی مدل در طول فرآیند صف کار اعمال شده بود، در زمانی که کار غیراصولی شود، اعمال نخواهد شد. بنابراین، اگر میخواهید با زیرمجموعهای از یک رابطه معین کار کنید، باید دوباره آن رابطه را در شغل صف خود محدود کنید.
یا برای جلوگیری از سریالی شدن روابط، می توانید
withoutRelations
در هنگام تنظیم مقدار خاصیت، متد را در مدل فراخوانی کنید. این روش نمونه ای از مدل را بدون روابط بارگذاری شده آن برمی گرداند:
/** * Create a new job instance. */public function __construct(Podcast $podcast){ $this->podcast = $podcast->withoutRelations();}
اگر از ارتقای ویژگی سازنده PHP استفاده می کنید و می خواهید نشان دهید که یک مدل Eloquent نباید روابط خود را سریالی کند، می توانید از
WithoutRelations
ویژگی استفاده کنید:
use Illuminate\Queue\Attributes\WithoutRelations; /** * Create a new job instance. */public function __construct( #[WithoutRelations] public Podcast $podcast) {}
اگر یک کار به جای یک مدل واحد، مجموعه یا آرایه ای از مدل های Eloquent را دریافت کند، زمانی که کار غیراصولی و اجرا می شود، روابط مدل های موجود در آن مجموعه بازیابی نمی شود. این برای جلوگیری از استفاده بیش از حد از منابع در مشاغلی است که با تعداد زیادی مدل سروکار دارند.
مشاغل منحصر به فرد
مشاغل منحصر به فرد نیاز به یک درایور حافظه پنهان دارند که از قفل ها پشتیبانی می کند . در حال حاضر، درایورهای
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; /** * Get the unique ID for the job. */ public function uniqueId(): string { 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\Contracts\Cache\Repository;use Illuminate\Support\Facades\Cache; class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique{ ... /** * Get the cache driver for the unique job lock. */ public function uniqueVia(): Repository { return Cache::driver('redis'); }}
اگر فقط باید پردازش همزمان یک کار را محدود کنید،
WithoutOverlapping
به جای آن از میان افزار کار استفاده کنید.
مشاغل رمزگذاری شده
لاراول به شما امکان می دهد از حریم خصوصی و یکپارچگی داده های شغلی از طریق
رمزگذاری
اطمینان حاصل کنید . برای شروع، به سادگی
ShouldBeEncrypted
رابط کاربری را به کلاس شغلی اضافه کنید. هنگامی که این رابط به کلاس اضافه شد، لاراول به طور خودکار کار شما را قبل از فشار دادن به یک صف رمزگذاری می کند:
<?php use Illuminate\Contracts\Queue\ShouldBeEncrypted;use Illuminate\Contracts\Queue\ShouldQueue; class UpdateSearchIndex implements ShouldQueue, ShouldBeEncrypted{ // ...}
میان افزار شغلی
میانافزارهای شغلی به شما این امکان را میدهند که منطق سفارشی را حول اجرای کارهای در صف بپیچید، و باعث کاهش حجم دیگ در خود کارها میشود. به عنوان مثال، روش زیر را در نظر بگیرید
handle
که از ویژگیهای محدودکننده نرخ Redis لاراول استفاده میکند تا فقط یک کار را هر پنج ثانیه پردازش کند:
use Illuminate\Support\Facades\Redis; /** * Execute the job. */public function handle(): void{ 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 Closure;use Illuminate\Support\Facades\Redis; class RateLimited{ /** * Process the queued job. * * @param \Closure(object): void $next */ public function handle(object $job, Closure $next): void { 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<int, object> */public function middleware(): array{ return [new RateLimited];}
میانافزار شغلی را میتوان به شنوندههای رویداد، پیامهای پستی و اعلانها نیز اختصاص داد.
محدود کردن نرخ
اگرچه ما به تازگی نشان دادیم که چگونه می توان میان افزار شغلی محدود کننده نرخ خود را بنویسید، لاراول در واقع شامل یک میان افزار محدود کننده نرخ است که ممکن است برای رتبه بندی مشاغل محدود از آن استفاده کنید. مانند
محدود کننده های نرخ مسیر
، محدود کننده های نرخ کار با استفاده از روش
RateLimiter
نما تعریف می شوند
for
.
به عنوان مثال، ممکن است بخواهید به کاربران اجازه دهید یک بار در ساعت از داده های خود نسخه پشتیبان تهیه کنند، در حالی که چنین محدودیتی برای مشتریان ممتاز اعمال نمی شود. برای انجام این کار، می توانید a را
RateLimiter
در
boot
متد خود تعریف کنید
AppServiceProvider
:
use Illuminate\Cache\RateLimiting\Limit;use Illuminate\Support\Facades\RateLimiter; /** * Bootstrap any application services. */public function boot(): void{ RateLimiter::for('backups', function (object $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<int, object> */public function middleware(): array{ return [new RateLimited('backups')];}
بازگرداندن یک کار با نرخ محدود دوباره در صف، تعداد کل کار را افزایش می دهد
attempts
. ممکن است بخواهید بر اساس آن، ویژگی های خود
tries
و
maxExceptions
طبقه شغلی خود را تنظیم کنید. یا، ممکن است بخواهید از این
retryUntil
روش
برای تعیین مدت زمانی استفاده کنید که کار دیگر نباید انجام شود.
اگر نمی خواهید یک کار زمانی که دارای نرخ محدود است دوباره امتحان شود، می توانید از
dontRelease
روش زیر استفاده کنید:
/** * Get the middleware the job should pass through. * * @return array<int, object> */public function middleware(): array{ 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<int, object> */public function middleware(): array{ return [new WithoutOverlapping($this->user->id)];}
هر گونه کار همپوشانی از همان نوع به صف بازگردانده می شود. همچنین میتوانید تعداد ثانیههایی را که باید قبل از انجام دوباره کار آزاد شده سپری شود را مشخص کنید:
/** * Get the middleware the job should pass through. * * @return array<int, object> */public function middleware(): array{ return [(new WithoutOverlapping($this->order->id))->releaseAfter(60)];}
اگر میخواهید فوراً کارهای همپوشانی را حذف کنید تا دوباره امتحان نشوند، میتوانید از
dontRelease
روش زیر استفاده کنید:
/** * Get the middleware the job should pass through. * * @return array<int, object> */public function middleware(): array{ return [(new WithoutOverlapping($this->order->id))->dontRelease()];}
میان
WithoutOverlapping
افزار از ویژگی قفل اتمی لاراول تغذیه می شود. گاهی اوقات، کار شما ممکن است به طور غیرمنتظره ای از کار بیفتد یا به گونه ای به پایان برسد که قفل باز نشود. بنابراین، می توانید با استفاده از روش، زمان انقضای قفل را به صراحت تعریف کنید
expireAfter
. به عنوان مثال، مثال زیر به لاراول دستور می دهد که
WithoutOverlapping
قفل را سه دقیقه پس از شروع پردازش کار آزاد کند:
/** * Get the middleware the job should pass through. * * @return array<int, object> */public function middleware(): array{ 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(): array { return [ (new WithoutOverlapping("status:{$this->provider}"))->shared(), ]; }} class ProviderIsUp{ // ... public function middleware(): array { return [ (new WithoutOverlapping("status:{$this->provider}"))->shared(), ]; }}
استثنائات تروتتلینگ
لاراول شامل یک
Illuminate\Queue\Middleware\ThrottlesExceptions
میان افزار است که به شما امکان می دهد استثنائات را کاهش دهید. هنگامی که کار تعداد معینی از استثناها را ایجاد می کند، تمام تلاش های بعدی برای اجرای کار تا زمانی که یک بازه زمانی مشخص سپری شود به تعویق می افتد. این میان افزار به ویژه برای مشاغلی که با سرویس های شخص ثالث که ناپایدار هستند در تعامل هستند مفید است.
به عنوان مثال، بیایید یک کار در صف را تصور کنیم که با یک API شخص ثالث تعامل دارد که شروع به ایجاد استثنا می کند. برای کاهش دریچه گاز، می توانید
ThrottlesExceptions
میان افزار را از روش کار خود برگردانید
middleware
. به طور معمول، این میان افزار باید با کاری که
تلاش های مبتنی بر زمان را
اجرا می کند جفت شود :
use DateTime;use Illuminate\Queue\Middleware\ThrottlesExceptions; /** * Get the middleware the job should pass through. * * @return array<int, object> */public function middleware(): array{ return [new ThrottlesExceptions(10, 5)];} /** * Determine the time at which the job should timeout. */public function retryUntil(): DateTime{ return now()->addMinutes(5);}
اولین آرگومان سازنده که توسط میان افزار پذیرفته شده است، تعداد استثناهایی است که کار می تواند قبل از throttle شدن ایجاد کند، در حالی که آرگومان سازنده دوم، تعداد دقیقه هایی است که باید قبل از انجام دوباره کار پس از پایان دادن به آن بگذرد. در مثال کد بالا، اگر کار 10 استثنا را در عرض 5 دقیقه پرتاب کند، 5 دقیقه قبل از تلاش مجدد کار صبر می کنیم.
هنگامی که یک کار یک استثنا ایجاد می کند اما آستانه استثنا هنوز به آن نرسیده است، معمولاً کار بلافاصله دوباره امتحان می شود. با این حال، میتوانید با فراخوانی
backoff
روش هنگام اتصال میانافزار به کار،
تعداد دقیقههایی که چنین کاری باید به تأخیر بیفتد را مشخص کنید :
use Illuminate\Queue\Middleware\ThrottlesExceptions; /** * Get the middleware the job should pass through. * * @return array<int, object> */public function middleware(): array{ return [(new ThrottlesExceptions(10, 5))->backoff(5)];}
در داخل، این میانافزار از سیستم کش لاراول برای اجرای محدود کردن نرخ استفاده میکند و نام کلاس کار به عنوان «کلید» حافظه پنهان استفاده میشود. می توانید با فراخوانی
by
روش هنگام اتصال میان افزار به شغل خود، این کلید را لغو کنید. این ممکن است مفید باشد اگر چندین شغل دارید که با یک سرویس شخص ثالث در حال تعامل هستند و دوست دارید آنها یک "سطل گاز" مشترک را به اشتراک بگذارند:
use Illuminate\Queue\Middleware\ThrottlesExceptions; /** * Get the middleware the job should pass through. * * @return array<int, object> */public function middleware(): array{ 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\RedirectResponse;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. */ public function store(Request $request): RedirectResponse { $podcast = Podcast::create(/* ... */); // ... ProcessPodcast::dispatch($podcast); return redirect('/podcasts'); }}
اگر می خواهید کاری را به صورت مشروط ارسال کنید، می توانید از روش های
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\RedirectResponse;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. */ public function store(Request $request): RedirectResponse { $podcast = Podcast::create(/* ... */); // ... ProcessPodcast::dispatch($podcast) ->delay(now()->addMinutes(10)); return redirect('/podcasts'); }}
سرویس صف آمازون 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\RedirectResponse;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. */ public function store(Request $request): RedirectResponse { $podcast = Podcast::create(/* ... */); // Create podcast... ProcessPodcast::dispatchSync($podcast); return redirect('/podcasts'); }}
مشاغل و معاملات پایگاه داده
در حالی که ارسال کارها در تراکنش های پایگاه داده کاملاً خوب است، باید مراقب باشید تا مطمئن شوید که کار شما واقعاً می تواند با موفقیت اجرا شود. هنگام ارسال یک کار در یک تراکنش، ممکن است قبل از انجام معامله مادر، کار توسط کارگر پردازش شود. وقتی این اتفاق میافتد، ممکن است هر بهروزرسانی که در طول تراکنش(های) پایگاه داده در مدلها یا رکوردهای پایگاه داده انجام دادهاید، هنوز در پایگاه داده منعکس نشود. علاوه بر این، هر مدل یا رکورد پایگاه داده ایجاد شده در تراکنش(های) ممکن است در پایگاه داده وجود نداشته باشد.
خوشبختانه، لاراول چندین روش برای حل این مشکل ارائه می دهد. ابتدا می توانید
after_commit
گزینه اتصال را در آرایه پیکربندی اتصال صف خود تنظیم کنید:
'redis' => [ 'driver' => 'redis', // ... 'after_commit' => true,],
هنگامی که
after_commit
گزینه وجود دارد
true
، می توانید کارها را در تراکنش های پایگاه داده ارسال کنید. با این حال، لاراول منتظر می ماند تا تراکنش های پایگاه داده والد باز انجام شود و سپس کار را ارسال کند. البته، اگر در حال حاضر هیچ تراکنش پایگاه داده باز نباشد، کار بلافاصله ارسال می شود.
اگر یک تراکنش به دلیل استثنایی که در طول تراکنش رخ میدهد، برگشت داده شود، کارهایی که در طی آن تراکنش ارسال شدهاند کنار گذاشته میشوند.
تنظیم
after_commit
گزینه پیکربندی رویtrue
همچنین باعث میشود هر شنونده رویداد، پیامهای پستی، اعلانها و رویدادهای پخش در صف پس از انجام تمام تراکنشهای پایگاه داده باز ارسال شود.
مشخص کردن Commit Dispatch Behavior Inline
after_commit
اگر گزینه پیکربندی اتصال صف را بر روی
تنظیم نکنید
true
، همچنان ممکن است نشان دهید که یک کار خاص باید پس از انجام تمام تراکنش های پایگاه داده باز ارسال شود. برای انجام این کار، می توانید
afterCommit
روش را به عملیات اعزام خود زنجیره بزنید:
use App\Jobs\ProcessPodcast; ProcessPodcast::dispatch($podcast)->afterCommit();
به همین ترتیب، اگر
after_commit
گزینه پیکربندی روی تنظیم شده باشد
true
، ممکن است نشان دهید که یک کار خاص باید فوراً بدون انتظار برای انجام هرگونه تراکنش پایگاه داده باز ارسال شود:
ProcessPodcast::dispatch($podcast)->beforeCommit();
زنجیره شغلی
Job chaining به شما امکان می دهد لیستی از کارهای در صف را مشخص کنید که باید پس از اجرای موفقیت آمیز کار اصلی به ترتیب اجرا شوند. اگر یک کار در دنباله شکست بخورد، بقیه کارها اجرا نمی شوند. برای اجرای یک زنجیره شغلی در صف، می توانید از
chain
روش ارائه شده توسط
Bus
نما استفاده کنید. گذرگاه فرمان لاراول یک جزء سطح پایینتر است که ارسال کار در صف در بالای آن ساخته شده است:
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();
علاوه بر زنجیرهای کردن نمونههای کلاس شغلی، میتوانید بستههای زنجیرهای را نیز انجام دهید:
Bus::chain([ new ProcessPodcast, new OptimizePodcast, function () { Podcast::update(/* ... */); },])->dispatch();
حذف مشاغل با استفاده از
$this->delete()
روش درون job مانع از پردازش مشاغل زنجیره ای نمی شود. زنجیره فقط در صورتی اجرا نمی شود که یک کار در زنجیره با شکست مواجه شود.
اتصال زنجیره ای و صف
اگر می خواهید اتصال و صفی را که باید برای کارهای زنجیره ای استفاده شود مشخص کنید، می توانید از
روش
onConnection
و استفاده کنید.
onQueue
این روشها اتصال صف و نام صف را مشخص میکنند که باید استفاده شود، مگر اینکه به کار صفبندی شده صریحاً یک اتصال / صف متفاوت اختصاص داده شود:
Bus::chain([ new ProcessPodcast, new OptimizePodcast, new ReleasePodcast,])->onConnection('redis')->onQueue('podcasts')->dispatch();
شکست های زنجیره ای
هنگام زنجیر کردن کارها، ممکن است از این
catch
روش برای تعیین یک بسته استفاده کنید که در صورت شکست کاری در زنجیره، باید فراخوانی شود. پاسخ تماس داده شده
Throwable
نمونه ای را دریافت می کند که باعث شکست کار شده است:
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();
از آنجایی که کالبکهای زنجیرهای سریالسازی میشوند و در زمان دیگری توسط صف لاراول اجرا میشوند، نباید از
$this
متغیر درون callbackهای زنجیرهای استفاده کنید.
سفارشی کردن صف یک اتصال
ارسال به یک صف خاص
با فشار دادن مشاغل به صف های مختلف، ممکن است مشاغل در صف خود را "دسته بندی" کنید و حتی تعداد کارگرانی را که به صف های مختلف اختصاص می دهید، اولویت بندی کنید. به خاطر داشته باشید، این کارها را به سمت "اتصالات" صف مختلف که توسط فایل پیکربندی صف شما تعریف شده است، سوق نمی دهد، بلکه فقط به صف های خاص در یک اتصال واحد می رسد. برای تعیین صف،
onQueue
هنگام ارسال کار از روش استفاده کنید:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use App\Models\Podcast;use Illuminate\Http\RedirectResponse;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. */ public function store(Request $request): RedirectResponse { $podcast = Podcast::create(/* ... */); // Create podcast... ProcessPodcast::dispatch($podcast)->onQueue('processing'); return redirect('/podcasts'); }}
از طرف دیگر، میتوانید صف شغل را با فراخوانی
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. */ 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\RedirectResponse;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. */ public function store(Request $request): RedirectResponse { $podcast = Podcast::create(/* ... */); // Create podcast... ProcessPodcast::dispatch($podcast)->onConnection('sqs'); return redirect('/podcasts'); }}
میتوانید
برای تعیین اتصال و صف برای یک کار،
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. */ 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;}
اگر به کنترل پویا روی حداکثر تلاش های یک کار خاص نیاز دارید، می توانید
tries
روشی را در آن کار تعریف کنید:
/** * Determine number of times the job may be attempted. */public function tries(): int{ return 5;}
تلاش های مبتنی بر زمان
بهعنوان جایگزینی برای تعریف چند بار انجام یک کار قبل از شکست، میتوانید زمانی را تعریف کنید که در آن کار دیگر نباید تلاش کرد. این اجازه می دهد تا یک کار هر تعداد بار در یک بازه زمانی مشخص انجام شود. برای تعیین زمانی که در آن کار دیگر نباید تلاش کرد، روشی را
retryUntil
به کلاس شغلی خود اضافه کنید. این متد باید یک
DateTime
نمونه
برگرداند :
use DateTime; /** * Determine the time at which the job should timeout. */public function retryUntil(): DateTime{ return now()->addMinutes(10);}
همچنین می توانید یک
tries
ویژگی یاretryUntil
متد را در شنوندگان رویداد در صف خود تعریف کنید .
حداکثر استثنائات
گاهی اوقات ممکن است بخواهید مشخص کنید که یک کار ممکن است بارها انجام شود، اما اگر تلاشهای مجدد توسط تعداد معینی از استثناهای کنترلنشده (برخلاف انتشار
release
مستقیم توسط روش) انجام شود، باید شکست بخورد. برای انجام این کار، می توانید یک
maxExceptions
ویژگی را در کلاس شغلی خود تعریف کنید:
<?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. */ public function handle(): void { Redis::throttle('key')->allow(10)->every(60)->then(function () { // Lock obtained, process the podcast... }, function () { // Unable to obtain lock... return $this->release(10); }); }}
در این مثال، اگر برنامه نتواند قفل Redis را به دست آورد، کار به مدت ده ثانیه آزاد می شود و تا 25 بار دوباره امتحان می شود. با این حال، اگر سه استثناء کنترل نشده توسط کار ایجاد شود، کار شکست خواهد خورد.
تایم اوت
اغلب، تقریباً می دانید که انتظار دارید کارهای در صف شما چقدر طول بکشد. به همین دلیل، لاراول به شما این امکان را می دهد که مقدار «تایم اوت» را مشخص کنید. بهطور پیشفرض، مقدار وقفه 60 ثانیه است. اگر یک کار بیش از تعداد ثانیه های مشخص شده توسط مقدار زمان وقفه در حال پردازش باشد، کارگری که کار را پردازش می کند با خطا خارج می شود. به طور معمول، کارگر به طور خودکار توسط مدیر فرآیند پیکربندی شده روی سرور شما راه اندازی مجدد می شود .
حداکثر تعداد ثانیهای که کارها میتوانند اجرا شوند را میتوان با استفاده از
--timeout
سوئیچ در خط فرمان Artisan مشخص کرد:
php artisan queue:work --timeout=30
اگر کار از حداکثر تلاشهای خود با زمانبندی مداوم بیشتر شود، بهعنوان ناموفق علامتگذاری میشود.
همچنین میتوانید حداکثر ثانیهای که یک کار باید در خود کلاس شغلی اجرا شود را تعیین کنید. اگر مهلت زمانی روی کار مشخص شده باشد، بر هر مهلت زمانی مشخص شده در خط فرمان ارجحیت خواهد داشت:
<?php namespace App\Jobs; class ProcessPodcast implements ShouldQueue{ /** * The number of seconds the job can run before timing out. * * @var int */ public $timeout = 120;}
گاهی اوقات، فرآیندهای مسدودکننده IO مانند سوکت ها یا اتصالات HTTP خروجی ممکن است به زمان تعیین شده شما احترام نگذارند. بنابراین، هنگام استفاده از این ویژگیها، همیشه باید سعی کنید با استفاده از APIهای آنها نیز یک بازه زمانی مشخص کنید. به عنوان مثال، هنگام استفاده از Guzzle، همیشه باید یک اتصال را مشخص کنید و مقدار مهلت زمانی را درخواست کنید.
پسوند
pcntl
PHP باید نصب شود تا زمانهای کاری مشخص شود. بهعلاوه، مقدار «تایماوت» یک کار باید همیشه کمتر از مقدار «تلاش مجدد بعد از» آن باشد . در غیر این صورت، کار ممکن است قبل از اینکه واقعاً اجرا یا به پایان برسد دوباره تلاش شود.
شکست در مهلت زمانی
اگر میخواهید نشان دهید که یک کار باید در زمان وقفه بهعنوان
ناموفق
علامتگذاری شود ، میتوانید
$failOnTimeout
ویژگی را در کلاس شغلی تعریف کنید:
/** * Indicate if the job should be marked as failed on timeout. * * @var bool */public $failOnTimeout = true;
رسیدگی به خطا
اگر در حین پردازش کار، یک استثنا ایجاد شود، کار به طور خودکار در صف باز میگردد، بنابراین ممکن است دوباره تلاش شود. کار تا زمانی که حداکثر تعداد دفعاتی که درخواست شما مجاز کرده است، به انتشار برسد. حداکثر تعداد تلاش توسط
--tries
سوئیچ استفاده شده در
queue:work
دستور Artisan تعریف می شود. از طرف دیگر، حداکثر تعداد تلاش ممکن است در خود کلاس شغلی تعریف شود. اطلاعات بیشتر در مورد اجرای صف کارگر را
می توانید در زیر بیابید
.
آزادسازی دستی یک شغل
گاهی اوقات ممکن است بخواهید به صورت دستی یک کار را در صف بازگردانید تا در فرصتی دیگر دوباره آن را امتحان کنید. می توانید این کار را با فراخوانی
release
متد انجام دهید:
/** * Execute the job. */public function handle(): void{ // ... $this->release();}
به طور پیشفرض، این
release
روش کار را برای پردازش فوری به صف باز میگرداند. با این حال، میتوانید به صف دستور دهید تا زمانی که تعداد ثانیه معینی سپری نشده است، با ارسال یک نمونه صحیح یا تاریخ به متد، کار را برای پردازش در دسترس قرار ندهد
release
:
$this->release(10); $this->release(now()->addSeconds(10));
شکست دستی یک کار
گاهی اوقات ممکن است لازم باشد یک کار را به صورت دستی به عنوان "شکست خورده" علامت گذاری کنید. برای انجام این کار، می توانید
fail
متد را فراخوانی کنید:
/** * Execute the job. */public function handle(): void{ // ... $this->fail();}
اگر میخواهید شغل خود را بهعنوان ناموفق علامتگذاری کنید، به دلیل استثنایی که پیدا کردهاید، میتوانید استثنا را به
fail
روش منتقل کنید. یا، برای راحتی، ممکن است یک پیام خطای رشته ای ارسال کنید که برای شما به استثنا تبدیل می شود:
$this->fail($exception); $this->fail('Something went wrong.');
Job Batching
ویژگی Job Batching لاراول به شما این امکان را میدهد که به راحتی دستهای از کارها را اجرا کنید و سپس زمانی که دستهای از کارها اجرا شدند، اقداماتی را انجام دهید. قبل از شروع، باید یک انتقال پایگاه داده ایجاد کنید تا جدولی بسازید که حاوی اطلاعات متا در مورد دسته های شغلی شما، مانند درصد تکمیل آنها باشد. این مهاجرت ممکن است با استفاده از دستور Artisan ایجاد شود
make:queue-batches-table
:
php artisan make: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. */ public function handle(): void { 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),])->before(function (Batch $batch) { // The batch has been created but no jobs have been added...})->progress(function (Batch $batch) { // A single job has completed successfully...})->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 ها استفاده کنید. علاوه بر این، از آنجایی که کارهای دستهای در تراکنشهای پایگاه داده پیچیده میشوند، عبارات پایگاهدادهای که commitهای ضمنی را راهاندازی میکنند، نباید در کارها اجرا شوند.
نام گذاری دسته ها
برخی از ابزارها مانند 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();
برعکس، شما ممکن است دستهای از کارها را در یک زنجیره با تعریف دستههایی در زنجیره اجرا کنید. برای مثال، میتوانید ابتدا دستهای از کارها را برای انتشار پادکستهای متعدد اجرا کنید و سپس دستهای از کارها را برای ارسال اعلانهای انتشار اجرا کنید:
use App\Jobs\FlushPodcastCache;use App\Jobs\ReleasePodcast;use App\Jobs\SendPodcastReleaseNotification;use Illuminate\Support\Facades\Bus; Bus::chain([ new FlushPodcastCache, Bus::batch([ new ReleasePodcast(1), new ReleasePodcast(2), ]), Bus::batch([ new SendPodcastReleaseNotification(1), new SendPodcastReleaseNotification(2), ]),])->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. */public function handle(): void{ 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. */public function handle(): void{ 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. */public function middleware(): array{ 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
use Illuminate\Support\Facades\Schedule; Schedule::command('queue:prune-batches')->daily();
به طور پیش فرض، تمام دسته های تمام شده که بیش از 24 ساعت از عمر آنها می گذرد، هرس می شوند. می توانید
hours
هنگام فراخوانی فرمان از این گزینه برای تعیین مدت زمان نگهداری داده های دسته ای استفاده کنید. به عنوان مثال، دستور زیر تمام دسته هایی را که بیش از 48 ساعت قبل تمام شده اند حذف می کند:
use Illuminate\Support\Facades\Schedule; Schedule::command('queue:prune-batches --hours=48')->daily();
گاهی اوقات، جدول شما
jobs_batches
ممکن است سوابق دستهای را برای دستههایی که هرگز با موفقیت تکمیل نشدهاند، جمعآوری کند، مانند دستههایی که یک کار شکست خورده و آن کار هرگز با موفقیت دوباره امتحان نشده است. میتوانید
queue:prune-batches
با استفاده از این گزینه دستور هرس کردن این رکوردهای دستهای ناتمام را بدهید
unfinished
:
use Illuminate\Support\Facades\Schedule; Schedule::command('queue:prune-batches --hours=48 --unfinished=72')->daily();
به همین ترتیب، جدول شما
jobs_batches
همچنین ممکن است سوابق دسته ای را برای دسته های لغو شده جمع آوری کند. میتوانید
queue:prune-batches
با استفاده از این گزینه دستور هرس کردن این رکوردهای دستهای لغو شده را بدهید
cancelled
:
use Illuminate\Support\Facades\Schedule; Schedule::command('queue:prune-batches --hours=48 --cancelled=72')->daily();
ذخیره سازی دسته ها در DynamoDB
لاراول همچنین از ذخیره متا اطلاعات دسته ای در DynamoDB به جای پایگاه داده رابطه ای پشتیبانی می کند . با این حال، شما باید به صورت دستی یک جدول DynamoDB ایجاد کنید تا تمام رکوردهای دسته ای ذخیره شود.
به طور معمول، این جدول باید نامگذاری شود
job_batches
، اما شما باید جدول را بر اساس مقدار مقدار
queue.batching.table
پیکربندی در فایل پیکربندی برنامه خود نامگذاری کنید
queue
.
پیکربندی جدول دسته ای DynamoDB
جدول
job_batches
باید دارای یک کلید پارتیشن اصلی رشته ای به نام
application
و یک کلید مرتب سازی اولیه رشته به نام باشد
id
. بخشی
application
از کلید شامل نام برنامه شما خواهد بود که توسط
name
مقدار پیکربندی در فایل پیکربندی برنامه شما تعریف شده است
app
. از آنجایی که نام برنامه بخشی از کلید جدول DynamoDB است، میتوانید از همان جدول برای ذخیره دستههای کار برای چندین برنامه لاراول استفاده کنید.
علاوه بر این،
ttl
اگر میخواهید از
هرس دستهای خودکار
استفاده کنید، میتوانید ویژگی را برای جدول خود تعریف کنید .
پیکربندی DynamoDB
سپس، AWS SDK را نصب کنید تا برنامه لاراول شما بتواند با آمازون DynamoDB ارتباط برقرار کند:
composer require aws/aws-sdk-php
سپس،
queue.batching.driver
مقدار گزینه پیکربندی را روی
dynamodb
. علاوه بر این، باید گزینه های پیکربندی
key
،
secret
و
region
پیکربندی را در
batching
آرایه پیکربندی تعریف کنید. این گزینه ها برای احراز هویت با AWS استفاده خواهند شد. هنگام استفاده از
dynamodb
درایور،
queue.batching.database
گزینه پیکربندی غیر ضروری است:
'batching' => [ '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' => 'job_batches',],
هرس دسته ها در DynamoDB
هنگام استفاده از DynamoDB برای ذخیره اطلاعات دسته شغلی، دستورات هرس معمولی که برای هرس دسته های ذخیره شده در یک پایگاه داده رابطه ای استفاده می شود، کار نمی کنند. در عوض، میتوانید از قابلیت TTL بومی DynamoDB برای حذف خودکار رکوردهای دستههای قدیمی استفاده کنید.
اگر جدول DynamoDB خود را با یک ویژگی تعریف کرده اید
ttl
، می توانید پارامترهای پیکربندی را برای آموزش لاراول تعریف کنید که چگونه رکوردهای دسته ای را هرس کند. مقدار
پیکربندی
queue.batching.ttl_attribute
نام ویژگی نگهدارنده TTL را مشخص میکند، در حالی که
queue.batching.ttl
مقدار پیکربندی تعداد ثانیههایی را که پس از آن میتوان یک رکورد دستهای را از جدول DynamoDB حذف کرد، نسبت به آخرین باری که رکورد بهروزرسانی شد، تعیین میکند:
'batching' => [ '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' => 'job_batches', 'ttl_attribute' => 'ttl', 'ttl' => 60 * 60 * 24 * 7, // 7 days...],
بسته شدن صف
به جای اعزام یک کلاس شغلی به صف، ممکن است یک تعطیلی نیز ارسال کنید. این برای کارهای سریع و ساده که باید خارج از چرخه درخواست فعلی اجرا شوند عالی است. هنگام ارسال بستهها به صف، محتوای کد بستهبندی بهصورت رمزنگاری امضا میشود تا در حین انتقال قابل تغییر نباشد:
$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 ها استفاده کنید.
اجرای صف کارگر
دستور
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
به یاد داشته باشید، کارگران صف فرآیندهای طولانی مدت هستند و وضعیت برنامه بوت شده را در حافظه ذخیره می کنند. در نتیجه، پس از شروع به کار متوجه تغییراتی در پایه کد شما نخواهند شد. بنابراین، در طول فرآیند استقرار، مطمئن شوید که کارگران صف خود را مجددا راه اندازی کنید . علاوه بر این، به یاد داشته باشید که هر حالت ایستا ایجاد یا اصلاح شده توسط برنامه شما به طور خودکار بین کارها بازنشانی نمی شود.
در غیر این صورت، می توانید
queue:listen
دستور را اجرا کنید. هنگام استفاده از
queue:listen
دستور، زمانی که می خواهید کد به روز شده خود را مجدداً بارگیری کنید یا وضعیت برنامه را بازنشانی کنید، لازم نیست کارگر را به صورت دستی راه اندازی مجدد کنید. با این حال، این دستور به طور قابل توجهی کارایی کمتری نسبت به
queue:work
دستور دارد:
php artisan queue:listen
در حال اجرا چند صف کارگران
برای اختصاص دادن چندین کارگر به یک صف و پردازش همزمان کارها، به سادگی باید چندین
queue:work
فرآیند را شروع کنید. این کار را می توان به صورت محلی از طریق چندین برگه در ترمینال یا در مرحله تولید با استفاده از تنظیمات پیکربندی مدیر فرآیند انجام داد.
هنگام استفاده از Supervisor
، می توانید از
numprocs
مقدار پیکربندی استفاده کنید.
تعیین اتصال و صف
همچنین می توانید مشخص کنید که کارگر باید از کدام اتصال صف استفاده کند. نام اتصال ارسال شده به
work
دستور باید با یکی از اتصالات تعریف شده در
config/queue.php
فایل پیکربندی شما مطابقت داشته باشد:
php artisan queue:work redis
بهطور پیشفرض، این
queue:work
فرمان فقط وظایف صف پیشفرض در یک اتصال معین را پردازش میکند. با این حال، شما می توانید صف کارگر خود را حتی بیشتر با پردازش صف های خاص برای یک اتصال خاص سفارشی کنید. به عنوان مثال، اگر تمام ایمیلهای شما در یک
emails
صف در
redis
اتصال صف پردازش میشوند، میتوانید دستور زیر را برای راهاندازی کارگری که فقط آن صف را پردازش میکند صادر کنید:
php artisan queue:work redis --queue=emails
پردازش تعداد مشخصی از مشاغل
این
--once
گزینه ممکن است برای دستور دادن به کارگر برای پردازش تنها یک کار از صف استفاده شود:
php artisan queue:work --once
این
--max-jobs
گزینه ممکن است برای دستور دادن به کارگر برای پردازش تعداد داده شده شغل و سپس خروج استفاده شود. این گزینه ممکن است زمانی مفید باشد که با
Supervisor
ترکیب شود، به طوری که کارگران شما پس از پردازش تعداد معینی از کارها، به طور خودکار راه اندازی مجدد شوند و هر حافظه ای که ممکن است انباشته شده باشند، آزاد شود:
php artisan queue:work --max-jobs=1000
پردازش همه مشاغل در صف و سپس خروج
این
--stop-when-empty
گزینه ممکن است برای دستور دادن به کارگر برای پردازش همه مشاغل و سپس خروج با ظرافت استفاده شود. اگر بخواهید پس از خالی شدن صف، ظرف را خاموش کنید، این گزینه میتواند هنگام پردازش صفهای لاراول در ظرف Docker مفید باشد:
php artisan queue:work --stop-when-empty
پردازش مشاغل برای تعداد معینی از ثانیه
این
--max-time
گزینه ممکن است برای دستور دادن به کارگر برای پردازش کارها برای تعداد ثانیه معین و سپس خروج استفاده شود. این گزینه ممکن است زمانی مفید باشد که با
Supervisor
ترکیب شود، به طوری که کارگران شما پس از پردازش کارها برای مدت زمان معین، به طور خودکار راه اندازی مجدد شوند و هر حافظه ای را که ممکن است انباشته کرده باشند، آزاد کنند:
# Process jobs for one hour and then exit...php artisan queue:work --max-time=3600
مدت زمان خواب کارگر
هنگامی که مشاغل در صف موجود هستند، کارگر به پردازش کارها بدون تاخیر در بین کارها ادامه می دهد. با این حال، این
sleep
گزینه تعیین می کند که در صورت عدم وجود شغل، کارگر چند ثانیه بخوابد. البته، در هنگام خواب، کارگر هیچ شغل جدیدی را پردازش نمی کند:
php artisan queue:work --sleep=3
حالت نگهداری و صف
در حالی که برنامه شما در حالت تعمیر و نگهداری است ، هیچ کار در صف رسیدگی نمی شود. هنگامی که برنامه از حالت تعمیر و نگهداری خارج شد، کارها به صورت عادی انجام می شوند.
برای اینکه کارگران صف خود را مجبور به پردازش کارها کنند حتی اگر حالت تعمیر و نگهداری فعال باشد، می توانید از
--force
گزینه زیر استفاده کنید:
php artisan queue:work --force
ملاحظات منابع
کارگران صف Daemon قبل از پردازش هر کار، چارچوب را "ریبوت" نمی کنند. بنابراین، پس از اتمام هر کار، باید منابع سنگین را آزاد کنید. برای مثال، اگر در حال دستکاری تصویر با کتابخانه GD هستید، باید
imagedestroy
پس از اتمام پردازش تصویر،
حافظه را آزاد کنید .
اولویت های صف
گاهی اوقات ممکن است بخواهید نحوه پردازش صف های خود را اولویت بندی کنید. به عنوان مثال، در فایل پیکربندی خود
config/queue.php
، می توانید پیش فرض
اتصال
queue
خود را روی
. با این حال، گاهی اوقات ممکن است بخواهید یک کار را به
صف اولویت مانند زیر فشار دهید:
redis
low
high
dispatch((new Job)->onQueue('high'));
برای راهاندازی کارگری که تأیید میکند که همه
high
کارهای صف قبل از ادامه کار در صف پردازش شدهاند
low
، فهرستی از نامهای صف با کاما را به
work
دستور ارسال کنید:
php artisan queue:work --queue=high,low
کارگران صف و استقرار
از آنجایی که کارگران صف فرآیندهای طولانی مدتی هستند، بدون راه اندازی مجدد متوجه تغییرات کد شما نخواهند شد. بنابراین، ساده ترین راه برای استقرار یک برنامه با استفاده از کارگران صف، راه اندازی مجدد کارگران در طول فرآیند استقرار شما است. میتوانید با صدور دستور، همه کارگران را بهخوبی راهاندازی مجدد کنید
queue:restart
:
php artisan queue:restart
این دستور به همه کارگران صف دستور می دهد که پس از اتمام پردازش کار فعلی خود، به آرامی خارج شوند تا هیچ شغل موجود از بین نرود. از آنجایی که صف کارگران هنگام
queue:restart
اجرای دستور خارج می شوند، باید یک مدیر فرآیند مانند
Supervisor
را اجرا کنید تا به طور خودکار کارگران صف را مجددا راه اندازی کند.
صف از حافظه نهان برای ذخیره سیگنال های راه اندازی مجدد استفاده می کند، بنابراین قبل از استفاده از این ویژگی باید بررسی کنید که درایور کش برای برنامه شما به درستی پیکربندی شده است.
انقضای شغل و مهلت زمانی
انقضای شغل
در فایل پیکربندی شما
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
جدول معمولاً در برنامه های جدید لاراول وجود دارد. با این حال، اگر برنامه شما حاوی یک انتقال برای این جدول نیست، می توانید از
make:queue-failed-table
دستور برای ایجاد مهاجرت استفاده کنید:
php artisan make: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.*/public function backoff(): int{ return 3;}
شما می توانید به راحتی با برگرداندن آرایه ای از مقادیر backoff از
backoff
متد، پشتیبان های "نمایی" را پیکربندی کنید. در این مثال، تأخیر در تلاش مجدد 1 ثانیه برای اولین بار، 5 ثانیه برای تلاش مجدد دوم، 10 ثانیه برای تلاش مجدد سوم، و 10 ثانیه برای هر تلاش مجدد بعدی، اگر تلاش های بیشتری باقی مانده باشد، خواهد بود:
/*** Calculate the number of seconds to wait before retrying the job.** @return array<int, int>*/public function backoff(): array{ 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; /** * Create a new job instance. */ public function __construct( public Podcast $podcast, ) {} /** * Execute the job. */ public function handle(AudioProcessor $processor): void { // Process uploaded podcast... } /** * Handle a job failure. */ public function failed(?Throwable $exception): void { // 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. */ public function register(): void { // ... } /** * Bootstrap any application services. */ public function boot(): void { 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
رویداد ارسال می شود. میتوانید به این رویداد در برنامهتان گوش دهید
AppServiceProvider
تا یک اعلان برای شما یا تیم توسعهتان ارسال شود:
use App\Notifications\QueueHasLongWaitTime;use Illuminate\Queue\Events\QueueBusy;use Illuminate\Support\Facades\Event;use Illuminate\Support\Facades\Notification; /** * Bootstrap any application services. */public function boot(): void{ Event::listen(function (QueueBusy $event) { Notification::route('mail', 'dev@example.com') ->notify(new QueueHasLongWaitTime( $event->connection, $event->queue, $event->size )); });}
آزمایش کردن
هنگام آزمایش کدی که کارها را ارسال می کند، ممکن است بخواهید به لاراول دستور دهید که واقعاً خود کار را اجرا نکند، زیرا کد کار را می توان به طور مستقیم و جدا از کدی که آن را ارسال می کند آزمایش کرد. البته، برای آزمایش خود شغل، میتوانید یک نمونه کار را نمونهسازی کنید و
handle
روش را مستقیماً در آزمون خود فراخوانی کنید.
شما می توانید از روش
Queue
نما
fake
برای جلوگیری از فشار دادن مشاغل در صف به صف استفاده کنید. پس از فراخوانی متد
Queue
نما
fake
، میتوانید ادعا کنید که برنامه تلاش کرده است تا کارها را به صف بکشد:
<?php use App\Jobs\AnotherJob;use App\Jobs\FinalJob;use App\Jobs\ShipOrder;use Illuminate\Support\Facades\Queue; test('orders can be shipped', function () { Queue::fake(); // Perform order shipping... // Assert that no jobs were pushed... Queue::assertNothingPushed(); // Assert a job was pushed to a given queue... Queue::assertPushedOn('queue-name', ShipOrder::class); // Assert a job was pushed twice... Queue::assertPushed(ShipOrder::class, 2); // Assert a job was not pushed... Queue::assertNotPushed(AnotherJob::class); // Assert that a Closure was pushed to the queue... Queue::assertClosurePushed(); // Assert the total number of jobs that were pushed... Queue::assertCount(3);});
<?php namespace Tests\Feature; use App\Jobs\AnotherJob;use App\Jobs\FinalJob;use App\Jobs\ShipOrder;use Illuminate\Support\Facades\Queue;use Tests\TestCase; class ExampleTest extends TestCase{ public function test_orders_can_be_shipped(): void { Queue::fake(); // Perform order shipping... // Assert that no jobs were pushed... Queue::assertNothingPushed(); // Assert a job was pushed to a given queue... Queue::assertPushedOn('queue-name', ShipOrder::class); // Assert a job was pushed twice... Queue::assertPushed(ShipOrder::class, 2); // Assert a job was not pushed... Queue::assertNotPushed(AnotherJob::class); // Assert that a Closure was pushed to the queue... Queue::assertClosurePushed(); // Assert the total number of jobs that were pushed... Queue::assertCount(3); }}
assertPushed
شما میتوانید روشهای یا روشهای
بسته را بپذیرید
assertNotPushed
تا ادعا کنید شغلی تحت فشار قرار گرفته است که یک «آزمون حقیقت» معین را گذرانده است. اگر حداقل یک شغل تحت فشار قرار گرفته باشد که آزمون صدق داده شده را با موفقیت پشت سر بگذارد، این ادعا موفقیت آمیز خواهد بود:
Queue::assertPushed(function (ShipOrder $job) use ($order) { return $job->order->id === $order->id;});
جعل کردن زیرمجموعه ای از مشاغل
اگر فقط باید کارهای خاصی را جعل کنید در حالی که به کارهای دیگر خود اجازه می دهید به طور عادی اجرا شوند، می توانید نام کلاس های مشاغلی را که باید جعل شوند به روش ارسال کنید
fake
:
test('orders can be shipped', function () { Queue::fake([ ShipOrder::class, ]); // Perform order shipping... // Assert a job was pushed twice... Queue::assertPushed(ShipOrder::class, 2);});
public function test_orders_can_be_shipped(): void{ Queue::fake([ ShipOrder::class, ]); // Perform order shipping... // Assert a job was pushed twice... Queue::assertPushed(ShipOrder::class, 2);}
با استفاده از روش زیر می توانید همه کارها را جعل کنید به جز مجموعه ای از مشاغل مشخص شده
except
:
Queue::fake()->except([ ShipOrder::class,]);
تست زنجیره های شغلی
برای آزمایش زنجیره های شغلی، باید از
Bus
قابلیت های جعلی نما استفاده کنید. روش
Bus
نما
assertChained
ممکن است برای اثبات اینکه
زنجیره ای از کارها
ارسال شده است استفاده شود. این
assertChained
روش آرایه ای از کارهای زنجیره ای را به عنوان اولین آرگومان خود می پذیرد:
use App\Jobs\RecordShipment;use App\Jobs\ShipOrder;use App\Jobs\UpdateInventory;use Illuminate\Support\Facades\Bus; Bus::fake(); // ... Bus::assertChained([ ShipOrder::class, RecordShipment::class, UpdateInventory::class]);
همانطور که در مثال بالا می بینید، آرایه مشاغل زنجیره ای ممکن است آرایه ای از نام کلاس های شغل باشد. با این حال، ممکن است مجموعهای از نمونههای شغلی واقعی را نیز ارائه کنید. هنگام انجام این کار، لاراول اطمینان حاصل می کند که نمونه های کار از یک کلاس هستند و دارای ارزش های یکسانی از مشاغل زنجیره ای ارسال شده توسط برنامه شما هستند:
Bus::assertChained([ new ShipOrder, new RecordShipment, new UpdateInventory,]);
میتوانید از این
assertDispatchedWithoutChain
روش برای تأیید اینکه یک کار بدون زنجیرهای از مشاغل تحت فشار قرار گرفته است استفاده کنید:
Bus::assertDispatchedWithoutChain(ShipOrder::class);
تست دسته های زنجیر شده
اگر زنجیره شغلی شما
شامل دستهای از مشاغل است
Bus::chainedBatch
، میتوانید با درج یک تعریف در ادعای زنجیرهای خود
اظهار کنید که دسته زنجیرهای با انتظارات شما مطابقت دارد :
use App\Jobs\ShipOrder;use App\Jobs\UpdateInventory;use Illuminate\Bus\PendingBatch;use Illuminate\Support\Facades\Bus; Bus::assertChained([ new ShipOrder, Bus::chainedBatch(function (PendingBatch $batch) { return $batch->jobs->count() === 3; }), new UpdateInventory,]);
آزمایش دسته های شغلی
روش
Bus
نما
assertBatched
ممکن است برای ادعای
ارسال
دسته ای از کارها
استفاده شود. بسته شدن داده شده به
assertBatched
روش نمونه ای از را دریافت می کند
Illuminate\Bus\PendingBatch
که ممکن است برای بازرسی کارهای درون دسته استفاده شود:
use Illuminate\Bus\PendingBatch;use Illuminate\Support\Facades\Bus; Bus::fake(); // ... Bus::assertBatched(function (PendingBatch $batch) { return $batch->name == 'import-csv' && $batch->jobs->count() === 10;});
میتوانید از این
assertBatchCount
روش برای تأیید اینکه تعداد معینی از دستهها ارسال شده است استفاده کنید:
Bus::assertBatchCount(3);
میتوانید
assertNothingBatched
برای تأیید اینکه هیچ دستهای ارسال نشده است استفاده کنید:
Bus::assertNothingBatched();
کار تست / تعامل دسته ای
علاوه بر این، ممکن است گاهی لازم باشد تعامل یک شغل فردی را با دسته اصلی آن آزمایش کنید. برای مثال، ممکن است لازم باشد آزمایش کنید که آیا یک کار پردازش بیشتر برای دسته خود را لغو کرده است یا خیر. برای انجام این کار، باید یک دسته جعلی را از طریق
withFakeBatch
روش به کار اختصاص دهید. این
withFakeBatch
روش یک تاپل حاوی نمونه کار و دسته جعلی را برمی گرداند:
[$job, $batch] = (new ShipOrder)->withFakeBatch(); $job->handle(); $this->assertTrue($batch->cancelled());$this->assertEmpty($batch->added);
تست تعاملات شغلی / صف
گاهی اوقات، ممکن است لازم باشد آزمایش کنید که یک کار در صف
دوباره به صف باز میگردد
. یا ممکن است لازم باشد آزمایش کنید که کار خود را حذف کرده است. می توانید این تعاملات صف را با نمونه سازی کار و فراخوانی
withFakeQueueInteractions
روش آزمایش کنید.
هنگامی که فعل و انفعالات صف کار جعلی شد، می توانید
handle
روش را در کار فراخوانی کنید. پس از فراخوانی کار، میتوان از روشهای
assetReleased
,
assertDeleted
و
assertFailed
برای اظهارنظر در برابر تعاملات صف شغل استفاده کرد:
use App\Jobs\ProcessPodcast; $job = (new ProcessPodcast)->withFakeQueueInteractions(); $job->handle(); $job->assertReleased(delay: 30);$job->assertDeleted();$job->assertFailed();
رویدادهای شغلی
با استفاده از
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. */ public function register(): void { // ... } /** * Bootstrap any application services. */ public function boot(): void { 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(); }});