Laravel 技巧之 定时任务

定时任务 Scheduled Tasks 是 Laravel 提供的组件之一,稍微上点规模的项目应该都会用到,好比开发微信应用时经过定时任务去刷新access token,好比天天定时发推送提现用户要记得签到。对于定时任务的基本用法,官网文档已经描述得很详细了,这里再也不多说。php

本文主要是介绍定时任务在实际应用中的两个小技巧:laravel

1. 多个任务并行执行

先简单介绍一下 Laravel 定时任务组件的基本原理:git

当cli初始化完毕以后,系统会调用 App\Console\Kernel::schedule 方法,也就是咱们定义定时任务列表的地方,这个方法里每调用一次 $schedule->command() 就会生成一个 Illuminate\Console\Scheduling\Event 对象并保存在 $schedule->events 数组里。当执行 php artisan scheduled:run 时,系统会遍历 $schedule->events,把当前时间须要执行的任务放在一个集合中,最后依次 串行执行 这些任务。github

这样作在大多数状况下是没有问题的,但有一些特殊的状况,好比在每月的第一天要给100W个用户发送邮件,同一批次的定时任务必须等到这些邮件所有发送完毕以后才会被执行,假如这些任务里有对执行时间十分敏感的任务,比每5分钟一次的数据快照,就会致使那个时间点数据的缺失。数组

这种状况下若是定时任务可以并行执行,就不会有这样的问题。Laravel 实际上提供了解决方案,但很奇怪文档里面并无提到,就是 runInBackground 方法,在定义定时任务时 $schedule->command('foo:bar')->everyMinutes()->runInBackground(); 就能够了。服务器

2. 负载均衡

随着业务逻辑的增多,定时任务也会愈来愈多,定时任务服务器的负载也会愈来愈高,甚至致使任务执行缓慢,然而咱们却只能在一台服务器上设置定时任务,若是在多台服务器上同时配置了定时任务,还会致使定时任务的重复执行。这个时候咱们但愿可以像队列那样,将定时任务分散到多台服务器上。微信

截止 v5.4.15,Laravel 尚未提供内置方案来解决这个问题,但只须要简单的改造就能够实现咱们须要的效果。首先咱们把将每一个定时任务里 handle 方法提取出来建立一个新的Job并继承 ShouldQueue,而后在定时任务的 handle 里直接 dispatch 对应的Job便可,这样本来的业务逻辑就会被队列处理掉,当系统有多台服务器在处理队列时,也就实现了咱们须要的负载均衡。负载均衡

可是这样毕竟仍是麻烦,每一个定时任务都要建立一个Command和一个Job,太费劲,因而我提交了一个 Proposal ,目前已经实现而且merge入5.4分支,相信下个版本你们就能用上了。用法也很简单,只须要建立一个继承 ShouldQueue的Job,而后在App\Console\Kernel::schedule 方法里定义spa

$schedule->job(new FooBarJob())->everyMinutes();

就能够了code

相关文章
相关标签/搜索