صف ها
- معرفی
- ایجاد اشتغال
- اعزام مشاغل
- بسته شدن صف
- اجرای The Queue Worker
- پیکربندی سرپرست
- مقابله با مشاغل ناموفق
- رویدادهای شغلی
معرفی
لاراول اکنون Horizon، داشبورد و سیستم پیکربندی زیبا را برای صفهای مجهز به Redis شما ارائه میکند. برای اطلاعات بیشتر ، مستندات کامل Horizon را بررسی کنید .
صفهای لاراول یک API یکپارچه را در میان انواع باطنهای صف مختلف، مانند Beanstalk، Amazon SQS، Redis یا حتی یک پایگاه داده رابطهای ارائه میکنند. صف ها به شما این امکان را می دهند که پردازش یک کار وقت گیر مانند ارسال ایمیل را به زمان دیگری موکول کنید. به تعویق انداختن این وظایف وقت گیر به شدت درخواست های وب را برای برنامه شما سرعت می بخشد.
فایل پیکربندی صف در ذخیره می شود
config/queue.php
. در این فایل پیکربندی های اتصال برای هر یک از درایورهای صف موجود در فریمورک را خواهید یافت که شامل پایگاه داده،
Beanstalkd
،
Amazon SQS
،
Redis
و یک درایور همزمان است که کارها را بلافاصله (برای استفاده محلی) اجرا می کند. یک
null
راننده صف نیز گنجانده شده است که مشاغل در صف را کنار می گذارد.
اتصالات در مقابل صف ها
قبل از شروع کار با صف های لاراول، مهم است که تمایز بین "اتصالات" و "صف" را درک کنید. در فایل پیکربندی شما
config/queue.php
یک گزینه پیکربندی وجود دارد
connections
. این گزینه یک اتصال خاص به یک سرویس پشتیبان مانند Amazon SQS، Beanstalk یا Redis را تعریف می کند. با این حال، هر اتصال صف داده شده ممکن است چندین "صف" داشته باشد که ممکن است به عنوان پشته های مختلف یا انبوهی از کارهای صف در نظر گرفته شود.
توجه داشته باشید که هر مثال پیکربندی اتصال در
queue
فایل پیکربندی حاوی یک
queue
ویژگی است. این صف پیشفرض است که کارها هنگام ارسال به یک اتصال خاص به آن ارسال میشوند. به عبارت دیگر، اگر یک کار را بدون مشخص کردن صریحاً مشخص کنید که باید به کدام صف ارسال شود، آن کار در صفی که در
queue
ویژگی پیکربندی اتصال
تعریف شده است قرار میگیرد :
// This job is sent to the default queue...Job::dispatch(); // This job is sent to the "emails" queue...Job::dispatch()->onQueue('emails');
برخی از برنامهها ممکن است نیازی به فشار دادن کارها به چند صف نداشته باشند، در عوض ترجیح میدهند یک صف ساده داشته باشند. با این حال، فشار دادن مشاغل به صف های متعدد می تواند به ویژه برای برنامه هایی مفید باشد که مایلند نحوه پردازش کارها را اولویت بندی یا تقسیم بندی کنند، زیرا کارگر صف لاراول به شما اجازه می دهد تا مشخص کنید کدام صف ها را باید بر اساس اولویت پردازش کند. به عنوان مثال، اگر مشاغل را به یک
high
صف فشار دهید، ممکن است کارگری را اجرا کنید که به آنها اولویت پردازش بالاتری می دهد:
php artisan queue:work --queue=high,default
نکات و پیش نیازهای راننده
پایگاه داده
برای استفاده از
database
درایور صف، به یک جدول پایگاه داده برای نگهداری کارها نیاز دارید. برای ایجاد مهاجرتی که این جدول را ایجاد می کند،
queue:table
دستور Artisan را اجرا کنید. پس از ایجاد مهاجرت، می توانید پایگاه داده خود را با استفاده از
migrate
دستور مهاجرت کنید:
php artisan queue:table php artisan migrate
ردیس
برای استفاده از
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
تا پردازش کار بعدی جلوگیری میکند.
سایر پیش نیازهای راننده
وابستگی های زیر برای درایورهای صف فهرست شده مورد نیاز است:
-
آمازون 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 ایجاد می شود. می توانید با استفاده از Artisan CLI یک کار در صف جدید ایجاد کنید:
php artisan make:job ProcessPodcast
کلاس تولید شده
Illuminate\Contracts\Queue\ShouldQueue
اینترفیس را پیادهسازی میکند و به لاراول نشان میدهد که کار باید به صف فشار داده شود تا به صورت ناهمزمان اجرا شود.
ساختار کلاس
کلاسهای کار بسیار ساده هستند، معمولاً فقط شامل یک
handle
متد هستند که وقتی کار توسط صف پردازش میشود فراخوانی میشود. برای شروع، بیایید نگاهی به یک کلاس شغلی بیاندازیم. در این مثال، وانمود میکنیم که یک سرویس انتشار پادکست را مدیریت میکنیم و باید فایلهای پادکست آپلود شده را قبل از انتشار پردازش کنیم:
<?php namespace App\Jobs; use App\AudioProcessor;use App\Podcast;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; protected $podcast; /** * Create a new job instance. * * @param Podcast $podcast * @return void */ public function __construct(Podcast $podcast) { $this->podcast = $podcast; } /** * Execute the job. * * @param AudioProcessor $processor * @return void */ public function handle(AudioProcessor $processor) { // Process uploaded podcast... }}
در این مثال، توجه داشته باشید که ما توانستیم یک
مدل Eloquent را
مستقیماً به سازنده کار در صف ارسال کنیم. به دلیل
SerializesModels
ویژگیای که کار از آن استفاده میکند، مدلهای Eloquent و روابط بارگذاری شده آنها بهخوبی سریالسازی میشوند و در هنگام پردازش کار، سریالسازی نمیشوند. اگر کار در صف شما یک مدل Eloquent را در سازنده خود بپذیرد، فقط شناسه مدل در صف سریال قرار می گیرد. هنگامی که کار واقعاً انجام می شود، سیستم صف به طور خودکار نمونه کامل مدل و روابط بارگذاری شده آن را از پایگاه داده بازیابی می کند. همه اینها برای برنامه شما کاملاً شفاف است و از مشکلاتی که ممکن است از سریالسازی نمونههای کامل مدل Eloquent ایجاد شود جلوگیری میکند.
این
handle
متد زمانی فراخوانی می شود که کار توسط صف پردازش شود. توجه داشته باشید که میتوانیم وابستگیهای مربوط به
handle
روش کار را تایپ کنیم.
ظرف سرویس
لاراول
به طور خودکار این وابستگی ها را تزریق می کند.
اگر میخواهید کنترل کاملی بر نحوه تزریق وابستگیهای کانتینر به
handle
روش در دست بگیرید، میتوانید از روش ظرف استفاده کنید
bindMethod
. متد
bindMethod
یک callback را می پذیرد که کار و کانتینر را دریافت می کند. در بازخوانی، شما آزاد هستید که
handle
روش را هر طور که می خواهید فراخوانی کنید. به طور معمول، شما باید این روش را از یک
ارائه دهنده خدمات
فراخوانی کنید :
use App\Jobs\ProcessPodcast; $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\Podcast $podcast * @return void */public function __construct(Podcast $podcast){ $this->podcast = $podcast->withoutRelations();}
میان افزار شغلی
میانافزار شغلی به شما امکان میدهد منطق سفارشی را حول اجرای کارهای در صف بپیچید، و باعث کاهش حجم دیگ در خود کارها شود. به عنوان مثال، روش زیر را در نظر بگیرید
handle
که از ویژگیهای محدودکننده نرخ 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];}
اعزام مشاغل
هنگامی که کلاس شغلی خود را نوشتید، می توانید آن را با استفاده از
dispatch
روش خود کار ارسال کنید. آرگومان های ارسال شده به
dispatch
متد به سازنده کار داده می شود:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. * * @param Request $request * @return Response */ public function store(Request $request) { // Create podcast... ProcessPodcast::dispatch($podcast); }}
ارسال با تاخیر
اگر میخواهید اجرای یک کار در صف را به تأخیر بیندازید، میتوانید
delay
هنگام ارسال یک کار از این روش استفاده کنید. به عنوان مثال، اجازه دهید مشخص کنیم که یک کار نباید تا 10 دقیقه پس از ارسال آن برای پردازش در دسترس باشد:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. * * @param Request $request * @return Response */ public function store(Request $request) { // Create podcast... ProcessPodcast::dispatch($podcast) ->delay(now()->addMinutes(10)); }}
سرویس صف آمازون SQS دارای حداکثر زمان تاخیر 15 دقیقه است.
دیسپاچینگ همزمان
اگر می خواهید یک کار را فوراً (به طور همزمان) ارسال کنید، می توانید از این
dispatchNow
روش استفاده کنید. هنگام استفاده از این روش، کار در صف قرار نمی گیرد و بلافاصله در فرآیند فعلی اجرا می شود:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. * * @param Request $request * @return Response */ public function store(Request $request) { // Create podcast... ProcessPodcast::dispatchNow($podcast); }}
زنجیره شغلی
Job chaining به شما امکان می دهد لیستی از کارهای در صف را مشخص کنید که باید پس از اجرای موفقیت آمیز کار اصلی به ترتیب اجرا شوند. اگر یک کار در دنباله شکست بخورد، بقیه کارها اجرا نمی شوند. برای اجرای یک زنجیره شغلی در صف، می توانید از این
withChain
روش در هر یک از کارهای قابل ارسال خود استفاده کنید:
ProcessPodcast::withChain([ new OptimizePodcast, new ReleasePodcast])->dispatch();
حذف مشاغل با استفاده از این
$this->delete()
روش مانع از پردازش مشاغل زنجیره ای نمی شود. زنجیره فقط در صورتی اجرا نمی شود که یک کار در زنجیره با شکست مواجه شود.
اتصال زنجیره ای و صف
اگر میخواهید اتصال و صف پیشفرض را که باید برای کارهای زنجیرهای استفاده شود، مشخص کنید، میتوانید از روش
allOnConnection
و استفاده کنید
allOnQueue
. این روشها اتصال صف و نام صف را مشخص میکنند که باید مورد استفاده قرار گیرد، مگر اینکه به کار در صف صریحاً یک اتصال / صف متفاوت اختصاص داده شود:
ProcessPodcast::withChain([ new OptimizePodcast, new ReleasePodcast])->dispatch()->allOnConnection('redis')->allOnQueue('podcasts');
سفارشی کردن صف و اتصال
ارسال به یک صف خاص
با فشار دادن مشاغل به صف های مختلف، ممکن است مشاغل در صف خود را "دسته بندی" کنید و حتی تعداد کارگرانی را که به صف های مختلف اختصاص می دهید، اولویت بندی کنید. به خاطر داشته باشید، این کارها را به سمت "اتصالات" صف مختلف که توسط فایل پیکربندی صف شما تعریف شده است، سوق نمی دهد، بلکه فقط به صف های خاص در یک اتصال واحد می رسد. برای تعیین صف،
onQueue
هنگام ارسال کار از روش استفاده کنید:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. * * @param Request $request * @return Response */ public function store(Request $request) { // Create podcast... ProcessPodcast::dispatch($podcast)->onQueue('processing'); }}
ارسال به یک اتصال خاص
اگر با چندین اتصال صف کار میکنید، میتوانید مشخص کنید که یک کار به کدام اتصال فشار داده شود. برای تعیین اتصال،
onConnection
هنگام ارسال کار از روش زیر استفاده کنید:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Jobs\ProcessPodcast;use Illuminate\Http\Request; class PodcastController extends Controller{ /** * Store a new podcast. * * @param Request $request * @return Response */ public function store(Request $request) { // Create podcast... ProcessPodcast::dispatch($podcast)->onConnection('sqs'); }}
میتوانید
برای تعیین اتصال و صف برای یک کار،
onConnection
و متدها را زنجیرهای کنید:
onQueue
ProcessPodcast::dispatch($podcast) ->onConnection('sqs') ->onQueue('processing');
همچنین، میتوانید
connection
ویژگی را در کلاس شغلی مشخص کنید:
<?php namespace App\Jobs; class ProcessPodcast implements ShouldQueue{ /** * The queue connection that should handle the job. * * @var string */ public $connection = 'sqs';}
تعیین حداکثر تلاشهای شغلی / مقادیر زمانبندی
حداکثر تلاش
یک روش برای تعیین حداکثر تعداد دفعاتی که ممکن است یک کار انجام شود، از طریق سوئیچ
--tries
در خط فرمان Artisan است:
php artisan queue:work --tries=3
با این حال، میتوانید با تعیین حداکثر تعداد تلاشها در خود کلاس شغلی، رویکرد دقیقتری داشته باشید. اگر حداکثر تعداد تلاش در کار مشخص شده باشد، بر مقدار ارائه شده در خط فرمان ارجحیت خواهد داشت:
<?php namespace App\Jobs; class ProcessPodcast implements ShouldQueue{ /** * The number of times the job may be attempted. * * @var int */ public $tries = 5;}
تلاش های مبتنی بر زمان
به عنوان جایگزینی برای تعریف اینکه چند بار ممکن است یک کار قبل از شکست آن تلاش شود، میتوانید زمانی را تعیین کنید که در آن کار باید مهلت زمانی انجام شود. این اجازه می دهد تا یک کار هر تعداد بار در یک بازه زمانی مشخص انجام شود. برای تعریف زمانی که یک کار باید در آن زمان به پایان برسد، یک
retryUntil
روش به کلاس شغلی خود اضافه کنید:
/** * Determine the time at which the job should timeout. * * @return \DateTime */public function retryUntil(){ return now()->addSeconds(5);}
همچنین میتوانید
retryUntil
روشی را روی شنوندگان رویداد در صف خود تعریف کنید.
تایم اوت
این
timeout
ویژگی برای PHP 7.1+ وpcntl
پسوند PHP بهینه شده است.
به همین ترتیب، حداکثر تعداد ثانیه هایی که کارها می توانند اجرا شوند را می توان با استفاده از
--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;}
محدود کردن نرخ
این ویژگی مستلزم آن است که برنامه شما بتواند با یک سرور Redis تعامل داشته باشد .
اگر برنامه شما با Redis تعامل داشته باشد، ممکن است مشاغل در صف خود را با زمان یا همزمان کاهش دهید. این ویژگی می تواند کمک کننده باشد زمانی که مشاغل در صف شما در حال تعامل با APIهایی هستند که دارای نرخ محدود نیز هستند.
به عنوان مثال، با استفاده از این
throttle
روش، میتوانید نوع خاصی از کار را در هر 60 ثانیه 10 بار اجرا کنید. اگر قفلی را نمیتوان دریافت کرد، معمولاً باید کار را در صف بازگردانید تا بعداً بتوان آن را دوباره امتحان کرد:
Redis::throttle('key')->allow(10)->every(60)->then(function () { // Job logic...}, function () { // Could not obtain lock... return $this->release(10);});
در مثال بالا، رشته
key
ممکن است هر رشته ای باشد که به طور منحصربفرد نوع شغلی را که می خواهید به محدودیت رتبه بندی کنید، مشخص می کند. برای مثال، ممکن است بخواهید کلید را بر اساس نام کلاس شغل و شناسههای مدلهای Eloquent که روی آن کار میکند، بسازید.
بازگرداندن یک کار throttled دوباره در صف همچنان تعداد کل کار را افزایش می دهد
attempts
.
از طرف دیگر، میتوانید حداکثر تعداد کارگرانی را که ممکن است به طور همزمان یک کار معین را پردازش کنند، مشخص کنید. این می تواند مفید باشد زمانی که یک کار در صف در حال تغییر منبعی است که فقط باید توسط یک کار در یک زمان اصلاح شود. برای مثال، با استفاده از این
funnel
روش، میتوانید کارهای یک نوع معین را محدود کنید تا فقط توسط یک کارگر در یک زمان پردازش شود:
Redis::funnel('key')->limit(1)->then(function () { // Job logic...}, function () { // Could not obtain lock... return $this->release(10);});
هنگام استفاده از محدودیت نرخ، تعیین تعداد تلاشهایی که کار شما برای اجرای موفقیتآمیز نیاز دارد، دشوار است. بنابراین، ترکیب محدود کردن نرخ با تلاشهای مبتنی بر زمان مفید است .
رسیدگی به خطا
اگر در حین پردازش کار، یک استثنا ایجاد شود، کار به طور خودکار در صف باز میشود، بنابراین ممکن است دوباره تلاش شود. کار تا زمانی که حداکثر تعداد دفعاتی که درخواست شما مجاز کرده است، به انتشار برسد. حداکثر تعداد تلاش توسط
--tries
سوئیچ استفاده شده در
queue:work
دستور Artisan تعریف می شود. از طرف دیگر، حداکثر تعداد تلاش ممکن است در خود کلاس شغلی تعریف شود. اطلاعات بیشتر در مورد اجرای صف کارگر را
می توانید در زیر بیابید
.
بسته شدن صف
به جای فرستادن یک کلاس شغلی به صف، میتوانید بسته شدن را نیز ارسال کنید. این برای کارهای سریع و ساده ای که باید خارج از چرخه درخواست فعلی اجرا شوند عالی است:
$podcast = App\Podcast::find(1); dispatch(function () use ($podcast) { $podcast->publish();});
هنگام ارسال بستهها به صف، محتویات کد بسته به صورت رمزنگاری امضا میشود، بنابراین نمیتوان آن را در حین انتقال تغییر داد.
اجرای The Queue Worker
لاراول شامل یک کارگر صف است که کارهای جدید را هنگامی که به صف فشار می دهند پردازش می کند. شما می توانید کارگر را با استفاده از
queue:work
دستور Artisan اجرا کنید. توجه داشته باشید که پس از
queue:work
شروع فرمان، تا زمانی که به صورت دستی متوقف شود یا ترمینال خود را ببندید، به اجرا ادامه خواهد داد:
php artisan queue:work
برای اینکه
queue:work
فرآیند به طور دائم در پسزمینه اجرا شود، باید از یک مانیتور فرآیند مانند Supervisor استفاده کنید تا اطمینان حاصل کنید که کارفرمای صف متوقف نمیشود.
به یاد داشته باشید، کارگران صف فرآیندهای طولانی مدت هستند و وضعیت برنامه بوت شده را در حافظه ذخیره می کنند. در نتیجه، پس از شروع به کار متوجه تغییراتی در پایه کد شما نخواهند شد. بنابراین، در طول فرآیند استقرار، مطمئن شوید که کارگران صف خود را مجددا راه اندازی کنید . علاوه بر این، به یاد داشته باشید که هر حالت ایستا ایجاد یا اصلاح شده توسط برنامه شما به طور خودکار بین کارها بازنشانی نمی شود.
در غیر این صورت، می توانید
queue:listen
دستور را اجرا کنید. هنگام استفاده از
queue:listen
دستور، زمانی که می خواهید کد به روز شده خود را مجدداً بارگیری کنید یا وضعیت برنامه را بازنشانی کنید، لازم نیست کارگر را به صورت دستی راه اندازی مجدد کنید. با این حال، این دستور به اندازه زیر کارآمد نیست
queue:work
:
php artisan queue:listen
تعیین اتصال و صف
همچنین می توانید مشخص کنید که کارگر باید از کدام اتصال صف استفاده کند. نام اتصال ارسال شده به
work
دستور باید با یکی از اتصالات تعریف شده در
config/queue.php
فایل پیکربندی شما مطابقت داشته باشد:
php artisan queue:work redis
شما می توانید صف کارگر خود را حتی بیشتر با پردازش صف های خاص برای یک اتصال خاص سفارشی کنید. به عنوان مثال، اگر همه ایمیلهای شما در یک
emails
صف در
redis
اتصال صف پردازش میشوند، میتوانید دستور زیر را برای راهاندازی کارگری که فقط آن صف را پردازش میکند صادر کنید:
php artisan queue:work redis --queue=emails
پردازش یک کار واحد
این
--once
گزینه ممکن است برای دستور دادن به کارگر برای پردازش تنها یک کار از صف استفاده شود:
php artisan queue:work --once
پردازش همه مشاغل در صف و سپس خروج
این
--stop-when-empty
گزینه ممکن است برای دستور دادن به کارگر برای پردازش همه مشاغل و سپس خروج با ظرافت استفاده شود. اگر میخواهید پس از خالی شدن صف، ظرف را خاموش کنید، این گزینه میتواند هنگام کار کردن صفهای لاراول در ظرف Docker مفید باشد:
php artisan queue:work --stop-when-empty
ملاحظات منابع
کارگران صف 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
گزینه مشخص میکند که پردازش اصلی صف لاراول قبل از کشتن یک کارگر صف که در حال پردازش یک کار است، چه مدت منتظر بماند. گاهی اوقات یک فرآیند صف کودک می تواند به دلایل مختلف "یخ زده" شود. این
--timeout
گزینه فرآیندهای منجمد شده را که از محدودیت زمانی مشخص شده فراتر رفته اند حذف می کند:
php artisan queue:work --timeout=60
گزینه پیکربندی
retry_after
و
--timeout
گزینه CLI متفاوت هستند، اما با هم کار می کنند تا اطمینان حاصل شود که مشاغل از بین نمی روند و کارها فقط یک بار با موفقیت پردازش می شوند.
مقدار
--timeout
باید همیشه حداقل چند ثانیه کوتاهتر ازretry_after
مقدار پیکربندی شما باشد. این تضمین می کند که کارگری که یک کار معین را پردازش می کند همیشه قبل از امتحان مجدد کار کشته می شود. اگر--timeout
گزینه شما بیشتر ازretry_after
مقدار پیکربندی شما باشد، ممکن است کارهای شما دو بار پردازش شود.
مدت زمان خواب کارگر
هنگامی که مشاغل در صف موجود هستند، کارگر به پردازش کارها بدون تاخیر بین آنها ادامه می دهد. با این حال، این
sleep
گزینه تعیین می کند که در صورت عدم وجود شغل جدید، کارگر چه مدت (در چند ثانیه) "خواب" خواهد داشت. هنگام خواب، کارگر هیچ شغل جدیدی را پردازش نمی کند - پس از بیدار شدن دوباره کارگر، کارها پردازش می شوند.
php artisan queue:work --sleep=3
پیکربندی سرپرست
نصب سوپروایزر
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=3autostart=trueautorestart=trueuser=forgenumprocs=8redirect_stderr=truestdout_logfile=/home/forge/app.com/worker.logstopwaitsecs=3600
در این مثال،
numprocs
دستورالعمل به Supervisor دستور میدهد که 8 فرآیند را اجرا کند
queue:work
و همه آنها را نظارت کند و در صورت شکست، آنها را به طور خودکار راهاندازی مجدد کند. شما باید
queue:work sqs
بخشی از
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
، کارها فقط یک بار انجام خواهند شد:
php artisan queue:work redis --tries=3
علاوه بر این، میتوانید مشخص کنید که لاراول چند ثانیه باید قبل از امتحان مجدد کاری که شکست خورده است، با استفاده از این
--delay
گزینه صبر کند. به طور پیش فرض، یک کار بلافاصله دوباره امتحان می شود:
php artisan queue:work redis --tries=3 --delay=3
اگر میخواهید تاخیر امتحان مجدد کار ناموفق را بر اساس هر شغل پیکربندی کنید، میتوانید این کار را با تعریف یک
retryAfter
ویژگی در کلاس شغلی در صف خود انجام دهید:
/** * The number of seconds to wait before retrying the job. * * @var int */public $retryAfter = 3;
تمیز کردن پس از انجام کارهای ناموفق
شما ممکن است
failed
روشی را مستقیماً در کلاس شغلی خود تعریف کنید، که به شما امکان می دهد در صورت بروز شکست، پاکسازی خاص کار را انجام دهید. این مکان عالی برای ارسال یک هشدار به کاربران شما یا برگرداندن هرگونه اقدام انجام شده توسط کار است. مواردی
Exception
که باعث شکست کار شده است به
failed
متد ارسال می شود:
<?php namespace App\Jobs; use App\AudioProcessor;use App\Podcast;use Exception;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Queue\SerializesModels; class ProcessPodcast implements ShouldQueue{ use InteractsWithQueue, Queueable, SerializesModels; protected $podcast; /** * Create a new job instance. * * @param Podcast $podcast * @return void */ public function __construct(Podcast $podcast) { $this->podcast = $podcast; } /** * Execute the job. * * @param AudioProcessor $processor * @return void */ public function handle(AudioProcessor $processor) { // Process uploaded podcast... } /** * The job failed to process. * * @param Exception $exception * @return void */ public function failed(Exception $exception) { // Send user notification of failure, etc... }}
failed
اگر کار با استفاده از متد ارسال شده باشد، متد فراخوانی نخواهد شدdispatchNow
.
رویدادهای شغلی ناموفق
اگر میخواهید رویدادی را ثبت کنید که در صورت شکست یک کار فراخوانی شود، میتوانید از این
Queue::failing
روش استفاده کنید. این رویداد یک فرصت عالی برای اطلاع تیم خود از طریق ایمیل یا
Slack
است . به عنوان مثال، ممکن است یک callback از رویدادی
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 }); }}
تلاش مجدد مشاغل ناموفق
برای مشاهده تمام کارهای ناموفق خود که در
failed_jobs
جدول پایگاه داده شما درج شده اند، می توانید از
queue:failed
دستور Artisan استفاده کنید:
php artisan queue:failed
این
queue:failed
دستور شناسه شغل، اتصال، صف و زمان شکست را فهرست می کند. شناسه شغل ممکن است برای امتحان مجدد کار ناموفق استفاده شود. به عنوان مثال، برای امتحان مجدد یک کار ناموفق که دارای شناسه است
5
، دستور زیر را صادر کنید:
php artisan queue:retry 5
برای امتحان مجدد همه کارهای ناموفق خود،
queue:retry
دستور را اجرا کرده و
all
به عنوان شناسه ارسال کنید:
php artisan queue:retry all
اگر می خواهید یک کار ناموفق را حذف کنید، می توانید از
queue:forget
دستور زیر استفاده کنید:
php artisan queue:forget 5
برای حذف تمام کارهای ناموفق خود، می توانید از
queue:flush
دستور زیر استفاده کنید:
php artisan queue:flush
نادیده گرفتن مدل های گمشده
هنگام تزریق یک مدل Eloquent به یک کار، قبل از قرار گرفتن در صف به طور خودکار سریال می شود و هنگامی که کار پردازش می شود، بازیابی می شود. با این حال، اگر در زمانی که کار در انتظار پردازش توسط کارگر بود، مدل حذف شده باشد، ممکن است کار شما با یک علامت شکست بخورد
ModelNotFoundException
.
برای راحتی کار، میتوانید با تنظیم
deleteWhenMissingModels
ویژگی شغل خود به صورت خودکار، کارهایی را که مدلهای گمشده دارند حذف کنید
true
:
/** * Delete the job if its models no longer exist. * * @var bool */public $deleteWhenMissingModels = true;
رویدادهای شغلی
با استفاده از
before
و
after
متدهای روی
Queue
نما
، میتوانید فراخوانهایی را مشخص کنید که قبل یا بعد از پردازش یک کار در صف اجرا شوند. این فراخوان ها فرصتی عالی برای انجام ثبت گزارش یا آمار افزایشی برای داشبورد هستند. به طور معمول، شما باید این روش ها را از یک
ارائه دهنده خدمات
فراخوانی کنید . به عنوان مثال، ممکن است از چیزی
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
نما
، میتوانید فراخوانهایی را مشخص کنید که قبل از تلاش کارگر برای واکشی کاری از یک صف اجرا شوند. به عنوان مثال، ممکن است برای بازگرداندن تراکنشهایی که توسط یک کار شکست خورده قبلی باز ماندهاند، یک بستن ثبت کنید:
Queue::looping(function () { while (DB::transactionLevel() > 0) { DB::rollBack(); }});