laravel综合话题队列——异步消息的定义
由上篇laravel综合话题:队列——异步消息的定义_队列,php_szuaudi的博客-CSDN博客
我们知道,laravel通过调用dispatch
方法分发任务,但实际上整个过程只是做异步消息的定义工作。在本篇中,我们探究任务类对象是怎么被持久化的。
任务的分发
一个非常关键的地方是PendingDispatch
类。在该类中有一个不能忽略的方法:
/**
* Handle the object's destruction.
*
* @return void
*/
public function __destruct()
{
app(Dispatcher::class)->dispatch($this->job);
}
在PendingDispatch
对象销毁时(可能是HTTP请求结束,脚本执行完成),将会执行该段代码,将会把我们定义的任务类对象传递给app(Dispatcher::class)->dispatch
方法。我们看一下app(Dispatcher::class)->dispatch($this->job);
的内容。
Dispatcher
Illuminate\Contracts\Bus\Dispatcher
是一个laravel的Contracts
接口,接口的实现类在laravel应用程序启动时创建及绑定。参见laravel中文文档laravel核心架构中的说明:Contracts |《Laravel 5.5 中文文档 5.5》| Laravel China 社区。
我们使用php artisan tinker
在控制台中打印出Dispatcher
绑定的类。
可以发现Dispatcher
接口绑定的是Illuminate\Bus\Dispatcher
类,我们在Illuminate\Bus\Dispatcher
类中查看Dispatcher
方法做了什么。
<?php
class Dispatcher implements QueueingDispatcher
{
...
/**
* Create a new command dispatcher instance.
*
* @param \Illuminate\Contracts\Container\Container $container
* @param \Closure|null $queueResolver
* @return void
*/
public function __construct(Container $container, Closure $queueResolver = null)
{
$this->container = $container;
$this->queueResolver = $queueResolver;
$this->pipeline = new Pipeline($container);
}
/**
* Dispatch a command to its appropriate handler.
*
* @param mixed $command
* @return mixed
*/
public function dispatch($command)
{
if ($this->queueResolver && $this->commandShouldBeQueued($command)) {
return $this->dispatchToQueue($command);
}
return $this->dispatchNow($command);
}
/**
* Dispatch a command to its appropriate handler in the current process.
*
* @param mixed $command
* @param mixed $handler
* @return mixed
*/
public function dispatchNow($command, $handler = null)
{
if ($handler || $handler = $this->getCommandHandler($command)) {
$callback = function ($command) use ($handler) {
return $handler->handle($command);
};
} else {
$callback = function ($command) {
return $this->container->call([$command, 'handle']);
};
}
return $this->pipeline->send($command)->through($this->pipes)->then($callback);
}
/**
* Determine if the given command should be queued.
*
* @param mixed $command
* @return bool
*/
protected function commandShouldBeQueued($command)
{
return $command instanceof ShouldQueue;
}
/**
* Dispatch a command to its appropriate handler behind a queue.
*
* @param mixed $command
* @return mixed
*
* @throws \RuntimeException
*/
public function dispatchToQueue($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);
}
return $this->pushCommandToQueue($queue, $command);
}
/**
* Push the command onto the given queue instance.
*
* @param \Illuminate\Contracts\Queue\Queue $queue
* @param mixed $command
* @return mixed
*/
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);
}
}
现在我们梳理一下大概过程:
dispatch
方法被调用。如果$this->queueResolver && $this->