剖析Laravel队列系统--初探

译文 GitHub https://github.com/yuansir/diving-laravel-zh

原文链接https://divinglaravel.com/queue-system/before-the-dive

Laravel 接收请求,做一些工作,然后向用户返回响应,这是处理请求的 Web 服务器的正常同步工作流程,但有时您需要在后台执行不中断或减慢的一些流程,例如在订单之后向用户发送发票电子邮件,你不想让用户等待邮件服务器接收请求,构建电子邮件消息,然后分派给用户,你只要向屏幕发送“谢谢!”给用户,电子邮件在后台准备和发送,他继续做他自己的事。

Laravel 配有内置的队列系统,可帮助您在后台运行任务,并通过简单的 API 来配置系统在不同情况下起作用。

您可以在 config/queue.php中管理队列配置,默认情况下它有使用不同队列驱动的几个连接,您可以看到项目中可以有多个队列连接,也可以使用多个队列驱动程序。

我们将研究不同的配置,但请先看看 API:

Queue::push(new SendInvoice($order));

return redirect('thank-you');

队列Queue facade 是 queue 容器别名,如果我们看看Queue\QueueServiceProvider ,我们可以看到这个别名是如何注册的:

protected function registerManager()
{
    $this->app->singleton('queue', function ($app) {
        return tap(new QueueManager($app), function ($manager) {
            $this->registerConnectors($manager);
        });
    });
}

所以 Queue facade 代理到在容器中注册为 Queue\QueueManager 类的单例,我们还将连接器注册到 Laravel 所支持使用的registerConnectors()的不同队列驱动程序中:

public function registerConnectors($manager)
{
    foreach (['Null', 'Sync', 'Database', 'Redis', 'Beanstalkd', 'Sqs'] as $connector) {
        $this->{"register{$connector}Connector"}($manager);
    }
}

该方法只需调用注册 register{DriverName}Connector方法,例如注册一个 Redis 连接器:

protected function registerRedisConnector($manager)
{
    $manager->addConnector('redis', function () {
        return new RedisConnector($this->app['redis']);
    });
}

addConnector() 方法将值存储到 QueueManager::$connectors 类属性。 连接器只是一个类,它包含一个 connect() 方法,它根据需要创建所需驱动的一个实例,方法看起来像在Queue\Connectors\RedisConnector里面:

public function connect(array $config)
{
    return new RedisQueue(
        $this->redis, $config['queue'],
        Arr::get($config, 'connection', $this->connection),
        Arr::get($config, 'retry_after', 60)
    );
}

所以现在 QueueManager 被注册到容器中,它知道如何连接到不同的内置队列驱动,如果我们看下这个类,我们将在最后找到一个__call() 魔术方法:

public function __call($method, $parameters)
{
    return $this->connection()->$method(...$parameters);
}

QueueManager 类中不存在的方法的所有调用将被发送到加载的驱动中,例如当我们调用 Queue::push() 方法时,所发生的是 manager 选择了连接到它的所需队列驱动 ,并在该驱动上调用 push 方法。

管理器如何知道要选哪个驱动?

让我们看下 connection() 方法

public function connection($name = null)
{
    $name = $name ?: $this->getDefaultDriver();

    if (! isset($this->connections[$name])) {
        $this->connections[$name] = $this->resolve($name);

        $this->connections[$name]->setContainer($this->app);
    }

    return $this->connections[$name];
}

当没有指定连接名称时,Laravel 将根据配置文件使用默认队列连接, getDefaultDriver() 返回config/queue.php['default']的值:

public function getDefaultDriver()
{
    return $this->app['config']['queue.default'];
}

一旦定义了驱动名称,管理器将检查该驱动是否已被加载,只有当它不是开始连接到该驱动程序并使用 resolve() 方法加载它时:

protected function resolve($name)
{
    $config = $this->getConfig($name);

    return $this->getConnector($config['driver'])
                ->connect($config)
                ->setConnectionName($name);
}

首先从 config/queue.php 文件加载所选连接的配置,然后将连接器定位到所选驱动,调用 connect() 方法,最后设置连接名称以供进一步使用。

现在我们知道在哪里可以找到 push 方法

是的,当您执行 Queue::push() 时,您正在使用的队列驱动中调用 push 方法,每个驱动以其自己的方式处理不同的操作,但 Laravel 为您提供了一个统一的接口,您可以使用它告诉队列管理器你使用了什么驱动程序。

如果我想使用不是内置的驱动程序怎么办?

简单来说,您可以使用自定义驱动的名称调用 Queue::addConnector() ,以及一个解释如何获取与该驱动程序的连接的闭包,还要确保您的连接器实现 Queue\Connectors\ConnectorInterface 接口。

注册连接器后,您可以使用任何使用此驱动的连接:

Queue::connection('my-connection')->push(...);

继续“准备队列作业”

转载请注明:  转载自Ryan 是菜鸟 | LNMP 技术栈笔记

如果觉得本篇文章对您十分有益,何不 打赏一下

谢谢打赏

本文链接地址: 剖析 Laravel 队列系统之初探

知识共享许可协议 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可


Original url: Access
Created at: 2018-12-19 13:53:31
Category: default
Tags: none

请先后发表评论
  • 最新评论
  • 总共0条评论