消除 Laravel 队列中的延迟

问题描述

我是 Laravel-Lumen 框架的粉丝。这些设计非常好,我们可以开始实施这些应用程序。但是有一个小问题。可能这不是问题,但在我看来这是一个小问题。让我解释一下。

例如,我有一个模型并且我正在使用弹性搜索。当一个模型创建(插入到数据库)然后我正在调度一个工作来索引这个模型。

public static function boot()
{
    parent::boot();

    static::created(function ($model) {
        $modelClass = get_class($model);
        lgi('>>> model created:' . $modelClass,$model);

        dispatch(new ElasticIndexerJob('creted',$model));
    });

    static::updated(function ($model) {
        $modelClass = get_class($model);
        lgi('>>> model updated:' . $modelClass,$model);

        dispatch(new ElasticIndexerJob('updated',$model));
    });

    static::deleted(function ($model) {
        $modelClass = get_class($model);
        lgi('>>> model deleted:' . $modelClass,$model);

        dispatch(new ElasticIndexerJob('deleted',$model));
    });
}

这会输出该日志:

[2021-04-18 11:28:36] local.INFO: /app/Models/Traits/Indexable.PHP:25 [
    ">>> model updated:App\\Models\\City",{
        "id": 3,"country_id": 85,"state_id": 1,"zip_code": "87506","name": "Nambe","lat": 35.8890389,"lng": -106.0657318,"status": "passive","created_at": "2021-04-13 09:38:09","updated_at": "2021-04-18 11:28:36"
    }
]

时间是 11:28:36。之后,我希望将日志输出排队。

[2021-04-18 11:28:38][27] Processing: App\Jobs\ElasticIndexerJob
[2021-04-18 11:28:38] local.INFO: /app/Jobs/ElasticIndexerJob.PHP:32 [
    "App\\Models\\City","updated","updated_at": "2021-04-18 11:28:36"
    }
]  
[2021-04-18 11:28:38][27] Processed:  App\Jobs\ElasticIndexerJob

队列输出时间为 11:28:38。如您所见,存在 2 seconds 延迟(或差异)。这个问题发生在所有队列(发送邮件、执行其他作业等)。发送邮件时这不是问题,但有时我需要实时执行。我想在我派遣时立即执行作业。

通常,如果我自己使用 beanstalkd,那么我可以立即接收消息(作业),并且我可以用该消息做一些事情。但是在 Laravel(或 Lumen)中存在延迟,这让我很恼火。

为什么 Laravel 有延迟,我该如何消除这个延迟?

我在数据库队列和 beanstalkd 队列中测试了这个。发生相同的行为:

QUEUE_CONNECTION=beanstalkd
; QUEUE_CONNECTION=database

注意:lgi() 函数一个 Log::info() 的信封

解决方法

您是否尝试过 dispatchSync,我不知道 Lumen 是否提供该功能。 Laravel dispatchSync

,

我找到了解决方案。我查看了 Laravel 的源代码,并在此文件中看到了该代码:Illuminate\Queue\Listener

/**
 * The amount of seconds to wait before polling the queue.
 *
 * @var int
 */
protected $sleep = 3;

我进行了更深入的调查,发现:

/**
 * Create the command with the listener options.
 *
 * @param  string  $connection
 * @param  string  $queue
 * @param  \Illuminate\Queue\ListenerOptions  $options
 * @return array
 */
protected function createCommand($connection,$queue,ListenerOptions $options)
{
    return array_filter([
        $this->phpBinary(),$this->artisanBinary(),'queue:work',$connection,'--once',"--name={$options->name}","--queue={$queue}","--backoff={$options->backoff}","--memory={$options->memory}","--sleep={$options->sleep}","--tries={$options->maxTries}",],function ($value) {
        return ! is_null($value);
    });
}

如您所见,有一个 CLI 参数是 --sleep=[second]。我们可以将此值设置为零 (0)。在那个队列工作者不等待处理下一个工作之后。

php artisan queue:work --sleep=0.1

我认为这些参数必须在文档中,但 Laravel 开发人员没有添加。或者我不知道我错过了这个。

编辑:如果您使用数据库作为队列后端,那么这种用法可以加载您的数据库。因为数据库驱动程序正在向 SELECT 表发送 jobs 查询。我建议在这种用法中使用 beanstalkd 驱动程序。

编辑 2:如果您将 --sleep 设置为 0(零),那么它可能会占用 CPU。

编辑 3:我现在看到了。可能我必须去看眼科医生 :S https://laravel.com/docs/8.x/queues#worker-sleep-duration