Laravel Crontab 支持的最小单位是分钟,怎么实现秒级执行的需求呢?

1,214 阅读1分钟

「这是我参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战

需求描述

今天接到一个需求,每三秒钟给客户端推送一次最新的在线人数。

分析

每三秒钟?要这么频繁吗?之前的最小颗粒度是每分钟哇。

调研了一波发现,我们可以结合异步任务的delay来实现。

核心代码

在 onQueue()函数后面调用 delay()函数

delay指定了延迟多久执行

XxxxxJob::dispatch()
    ->onQueue(QueueNameBuilder::getName(QueueNameBuilder::PUSH_DATING_COUNT))
    ->delay(now()->addSeconds($delay));

需求实现

比如我们的需求是,每三秒钟给客户端推送一次数据。

我的设计是这样的:

异步任务代码

<?php

namespace App\Console\Crontab;

use App\Jobs\PushDatingCountJob;
use App\Model\House\HouseOpen;
use App\Model\Queue\QueueNameBuilder;

class PushDatingCount extends BaseCrontab
{
    const RATE_SECOND = 3; //每三秒发送一次 延迟实现

    public function __invoke()
    {
        $times = 60 / self::RATE_SECOND;
        $delayTimes = [];
        for ($i = 0; $i < $times; $i++) {
            $delayTimes[] = $i * 3;
        }

        foreach ($delayTimes as $delay) {
            PushDatingCountJob::dispatch()
                ->onQueue(QueueNameBuilder::getName(QueueNameBuilder::PUSH_DATING_COUNT))
                ->delay(now()->addSeconds($delay));
        }
    }

}

Kernel

<?php

namespace App\Console;

.
.
.

class Kernel extends ConsoleKernel
{
    /**
     * The Artisan commands provided by your application.
     *
     * @var array
     */
    protected $commands = [
        //
    ];

    /**
     * Define the application's command schedule.
     *
     * @param \Illuminate\Console\Scheduling\Schedule $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        .
        .
        .

        //每分钟执行一次
        $schedule->call(new PushDatingCount())
            ->cron("* * * * *")
            ->name("push_dating_count")
            ->onOneServer();
    }

    /**
     * Register the commands for the application.
     *
     * @return void
     */
    protected function commands()
    {
        $this->load(__DIR__ . '/Commands');

        require base_path('routes/console.php');
    }
}

通过这个思路我们就实现了需求。

更多的使用技巧

本地测试阶段不方面使用异步任务队列怎么办呢?

我们可以使用dispatchNow()

比如:

本地执行,不使用异步队列的情况:

        UserConfirmForAdmin::dispatchNow([
            'data' => $data,
            'adminId' => $adminId,
        ]);

使用异步任务队列执行的情况:

        UserConfirmForAdmin::dispatch([
            'data' => $data,
            'adminId' => $adminId,
        ])->onQueue(QueueNameBuilder::getName(QueueNameBuilder::USER_CONFIRM_FOR_ADMIN));

如何可视化查询异步任务的执行情况呢?

我们可以使用 horizon

我们通过仪表盘能够非常方便的进行数据监控,查看数据指标,查看最近失败的异步任务,可以通过后台重新执行异步任务

image.png

重点说一下执行失败的异步任务,后台是支持查看数据参数的,方便我们定位问题。

image.png

硬核文章推荐

PHP转Go 2021年年中总结

如何第一时间收到接口报错?不用测试妹子再质疑你是不是接口挂了。

Git使用实战:多人协同开发,紧急修复线上bug的Git操作指南。

性能优化反思:不要在for循环中操作DB

性能优化反思:不要在for循环中操作DB 进阶版

最后

👍🏻:觉得有收获请点个赞鼓励一下!

🌟:收藏文章,方便回看哦!

💬:评论交流,互相进步!