需求描述
今天接到一个需求,每三秒钟给客户端推送一次最新的在线人数。
分析
每三秒钟?要这么频繁吗?之前的最小颗粒度是每分钟哇。
调研了一波发现,我们可以结合异步任务的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
我们通过仪表盘能够非常方便的进行数据监控,查看数据指标,查看最近失败的异步任务,可以通过后台重新执行异步任务
重点说一下执行失败的异步任务,后台是支持查看数据参数的,方便我们定位问题。