原文連接https://divinglaravel.com/queue-system/pushing-jobs-to-queuephp
There are several ways to push jobs into the queue:
有幾種方法能夠將做業推送到隊列中:laravel
Queue::push(new InvoiceEmail($order)); Bus::dispatch(new InvoiceEmail($order)); dispatch(new InvoiceEmail($order)); (new InvoiceEmail($order))->dispatch();
As explained in a previous dive, calls on the Queue
facade are calls on the queue driver your app uses, calling the push
method for example is a call to the push
method of the Queue\DatabaseQueue
class in case you're using the database queue driver.數據庫
There are several useful methods you can use:閉包
調用Queue
facade是對應用程序使用的隊列驅動的調用,若是你使用數據庫隊列驅動,調用push
方法是調用Queue\DatabaseQueue
類的push
方法。app
有幾種有用的方法能夠使用:ide
// 將做業推送到特定的隊列 Queue::pushOn('emails', new InvoiceEmail($order)); // 在給定的秒數以後推送做業 Queue::later(60, new InvoiceEmail($order)); // 延遲後將做業推送到特定的隊列 Queue::laterOn('emails', 60, new InvoiceEmail($order)); // 推送多個做業 Queue::bulk([ new InvoiceEmail($order), new ThankYouEmail($order) ]); // 推送特定隊列上的多個做業 Queue::bulk([ new InvoiceEmail($order), new ThankYouEmail($order) ], null, 'emails');
After calling any of these methods, the selected queue driver will store the given information in a storage space for workers to pick up on demand.函數
調用這些方法以後,所選擇的隊列驅動會將給定的信息存儲在存儲空間中,供workers按需獲取。ui
Dispatching jobs to queue using the command bus gives you extra control; you can set the selected connection
, queue
, and delay
from within your job class, decide if the command should be queued or run instantly, send the job through a pipeline before running it, actually you can even handle the whole queueing process from within your job class.this
The Bus
facade proxies to the Contracts\Bus\Dispatcher
container alias, this alias is resolved into an instance of Bus\Dispatcher
inside Bus\BusServiceProvider
:spa
使用命令總線調度做業進行排隊能夠給你額外控制權; 您能夠從做業類中設置選定的connection
, queue
, and delay
來決定命令是否應該排隊或當即運行,在運行以前經過管道發送做業,實際上你甚至能夠從你的做業類中處理整個隊列過程。
Bug
facade代理到 Contracts\Bus\Dispatcher
容器別名,此別名解析爲Bus\Dispatcher
內的Bus\BusServiceProvider
的一個實例:
$this->app->singleton(Dispatcher::class, function ($app) { return new Dispatcher($app, function ($connection = null) use ($app) { return $app[QueueFactoryContract::class]->connection($connection); }); });
因此Bus::dispatch()
調用的 dispatch()
方法是 Bus\Dispatcher
類的:
public function dispatch($command) { if ($this->queueResolver && $this->commandShouldBeQueued($command)) { return $this->dispatchToQueue($command); } else { return $this->dispatchNow($command); } }
This method decides if the given job should be dispatched to queue or run instantly, the commandShouldBeQueued()
method checks if the job class is an instance of Contracts\Queue\ShouldQueue
, so using this method your job will only be queued in case you implement the ShouldQueue
interface.
We're not going to look into dispatchNow
in this dive, it'll be discussed in detail when we dive into how workers run jobs. For now let's look into how the Bus dispatches your job to queue:
該方法決定是否將給定的做業分派到隊列或當即運行,commandShouldBeQueued()
方法檢查做業類是不是 Contracts\Queue\ShouldQueue
, 的實例,所以使用此方法,您的做業只有繼承了ShouldQueue
接口才會被放到隊列中。
咱們不會在這篇中深刻dispatchNow
,咱們將在深刻worker如何執行做業中詳細討論。 如今咱們來看看總線如何調度你的工做隊列:
public function dispatchToQueue($command) { $connection = isset($command->connection) ? $command->connection : null; $queue = call_user_func($this->queueResolver, $connection); if (! $queue instanceof Queue) { throw new RuntimeException('Queue resolver did not return a Queue implementation.'); } if (method_exists($command, 'queue')) { return $command->queue($queue, $command); } else { return $this->pushCommandToQueue($queue, $command); } }
First Laravel checks if a connection
property is defined in your job class, using the property you can set which connection Laravel should send the queued job to, if no property was defined null
will be used and in such case Laravel will use the default connection.
Using the connection value, Laravel uses a queueResolver closure to build the instance of the queue driver that should be used, this closure is set inside Bus\BusServiceProvider
while registering the Dispatcher instance:
首先 Laravel會檢查您的做業類中是否認義了connection
屬性,使用這個屬性能夠設置Laravel應該將排隊做業發送到哪一個鏈接,若是未定義任何屬性,將使用null屬性,在這種狀況下Laravel將使用默認鏈接。
經過設置的鏈接,Laravel使用一個queueResolver閉包來構建應該使用哪一個隊列驅動的實例,當註冊調度器實例的時候這個閉包在Bus\BusServiceProvider
中被設置:
function ($connection = null) use ($app) { return $app[Contracts\Queue\Factory::class]->connection($connection); }
Contracts\Queue\Factory
is an alias for Queue\QueueManager
, so in other words this closure returns an instance of QueueManager and sets the desired connection for the manager to know which driver to use.
Finally the dispatchToQueue
method checks if the job class has a queue
method, if that's the case the dispatcher will just call this method giving you full control over how the job should be queued, you can select the queue, assign delay, set maximum retries, timeout, etc...
In case no queue
method was found, a call to pushCommandToQueue()
calls the proper push
method on the selected queue driver:
Contracts\Queue\Factory
是Queue\QueueManager
的別名,換句話說,該閉包返回一個QueueManager
實例,併爲manager
設置所使用的隊列驅動須要的鏈接。
最後,dispatchToQueue
方法檢查做業類是否具備queue
方法,若是調度器調用此方法,能夠徹底控制做業排隊的方式,您能夠選擇隊列,分配延遲,設置最大重試次數, 超時等
若是沒有找到 queue
方法,對 pushCommandToQueue()
的調用將調用所選隊列驅動上的push
方法:
protected function pushCommandToQueue($queue, $command) { if (isset($command->queue, $command->delay)) { return $queue->laterOn($command->queue, $command->delay, $command); } if (isset($command->queue)) { return $queue->pushOn($command->queue, $command); } if (isset($command->delay)) { return $queue->later($command->delay, $command); } return $queue->push($command); }
The dispatcher checks for queue
and delay
properties in your Job class & picks the appropriate queue method based on that.
調度器檢查Job類中的 queue
和 delay
,並根據此選擇適當的隊列方法。
Yes, you can also set a tries
and timeout
properties and the queue driver will use these values as well, here's how your job class might look like:
是的,您還能夠設置一個tries
和 timeout
屬性,隊列驅動也將使用這些值,如下工做類示例:
class SendInvoiceEmail{ public $connection = 'default'; public $queue = 'emails'; public $delay = 60; public $tries = 3; public $timeout = 20; }
Using the dispatch()
global helper you can do something like this:
使用 dispatch()
全局幫助方法,您能夠執行如下操做:
dispatch(new InvoiceEmail($order)) ->onConnection('default') ->onQueue('emails') ->delay(60);
This only works if you use the Bus\Queueable
trait in your job class, this trait contains several methods that you may use to set some properties on the job class before dispatching it, for example:
這隻有在您在做業類中使用 Bus\Queueable
trait時纔有效,此trait包含幾種方法,您能夠在分發做業類以前在做業類上設置一些屬性,例如:
public function onQueue($queue) { $this->queue = $queue; return $this; }
Here's the trick:
這是訣竅:
function dispatch($job) { return new PendingDispatch($job); }
This is the definition of the dispatch()
helper in Foundation/helpers.php
, it returns an instance of Bus\PendingDispatch
and inside this class we have methods like this:
這是在Foundation/helpers.php
中的dispatch()
幫助方法的定義,它返回一個Bus\PendingDispatch
的實例,而且在這個類中,咱們有這樣的方法:
public function onQueue($queue) { $this->job->onQueue($queue); return $this; }
So when we do dispatch(new JobClass())->onQueue('default')
, the onQueue
method of PendingDispatch
will call the onQueue
method on the job class, as we mentioned earlier job classes need to use the Queueable
trait for all this to work.
因此當咱們執行 dispatch(new JobClass())->onQueue('default')
, 時,PendingDispatch
的 onQueue
方法將調用job類上的 onQueue
方法,如前所述,做業類須要使用全部這些的 Queueable
trait來工做。
Once you do dispatch(new JobClass())->onQueue('default')
you'll have the job instance ready for dispatching, the actual work happens inside PendingDispatch::__destruct()
:
一旦你執行了 dispatch(new JobClass())->onQueue('default')
,你將讓做業實例準備好進行調度,實際的工做發生在 PendingDispatch::__destruct()
中:
public function __destruct() { app(Dispatcher::class)->dispatch($this->job); }
This method, when called, will resolve an instance of Dispatcher
from the container and call the dispatch()
method on it. A __destruct()
is a PHP magic method that's called when all references to the object no longer exist or when the script terminates, and since we don't store a reference to the PendingDispatch
instance anywhere the __destruct
method will be called immediately:
調用此方法時,將從容器中解析 Dispatcher
的一個實例,而後調用它的dispatch()
方法。 destruct()是一種PHP魔術方法,當對對象的全部引用再也不存在或腳本終止時,都會調用,由於咱們不會當即在 __destruct
方法中存儲對PendingDispatch
實例的引用,
// Here the destructor will be called rightaway dispatch(new JobClass())->onQueue('default'); // 若是咱們調用unset($temporaryVariable),那麼析構函數將被調用 // 或腳本完成執行時。 $temporaryVariable = dispatch(new JobClass())->onQueue('default');
You can use the Bus\Dispatchable
trait on your job class to be able to dispatch your jobs like this:
您能夠使用工做類上的 Bus\Dispatchable
trait來調度您的工做,以下所示:
(new InvoiceEmail($order))->dispatch();
Here's how the dispatch method of Dispatchable
looks like:
調度方法 Dispatchable
看起來像這樣:
public static function dispatch() { return new PendingDispatch(new static(...func_get_args())); }
As you can see it uses an instance of PendingDispatch
, that means we can do something like:
正如你能夠看到它使用一個 PendingDispatch
的實例,這意味着咱們能夠作一些像這樣的事:
(new InvoiceEmail($order))->dispatch()->onQueue('emails');
轉載請註明: 轉載自Ryan是菜鳥 | LNMP技術棧筆記
若是以爲本篇文章對您十分有益,何不 打賞一下
本文連接地址: 剖析Laravel隊列系統--推送做業到隊列