• Laravel/Lumen 任务调度简易入门说明


    前提

    Laravel 中任务调度简化了服务器系统中 Cron 的操作,使得 计划任务 的实现更为简便。

    这里主要以 Laravel 自带的消息队列进行说明,了解其间运行关系可以让我们更清晰的进行代码实现。

    下方代码以 Lumen 9.x 框架进行举例,与 Laravel 应无二致。

    中文参考文档:任务调度 - Laravel 9.x

    定义任务调度

    我们称之为 计划任务周期性任务 均可。因为他的目的即是如此。

    首先编辑 App\Console\Kernel 类,默认内容如下:

    
    
    namespace App\Console;
    
    use Illuminate\Console\Scheduling\Schedule;
    use Laravel\Lumen\Console\Kernel as ConsoleKernel;
    
    class Kernel extends ConsoleKernel {
    
        /**
         * The Artisan commands provided by your application.
         *
         * @var array
         */
        protected $commands = [
        ];
    
        /**
         * Define the application's command schedule.
         *
         * @param Schedule $schedule
         *
         * @return void
         */
        protected function schedule(Schedule $schedule): void {
            // TODO:
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    例如我们需要在 每周一凌晨时段 执行业务统计任务(假设统计上一周订单量、销售额)

    周期定义可参阅:任务调度 - 调度频率选项

    schedule 方法中先写上如下代码:

    protected function schedule(Schedule $schedule): void {
        $schedule->job()                // 到达指定周期执行的目标任务,此处我们的目的是生产一条消息队列
            ->withoutOverlapping()      // 避免任务重复
            ->timezone('Asia/Shanghai') // 指定时区
            ->weeklyOn([1], '03:00');   // 定义时间:每周一 03:00 AM 执行。如果周一、周三、周六皆需要运行则可将第一参数修改为 [1, 3, 6]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    IDE 会对 job 方法报出警告,因为我们还未添加其对应的消息队列

    添加消息队列

    Laravel/Lumen 框架中支持多种消息队列驱动:sqsdatabaseredisbeanstalkd,我们以 redis 为例。此处假设你已做好 redis 队列相关环境以及配置。

    我们在 App\Jobs 中编写一个 WeeklyStatisticsJob 类:

    
    
    namespace App\Jobs;
    
    class WeeklyStatisticsJob extends Job {
    
        public function __construct() {
        }
    
        /**
         * Execute the job.
         *
         * @return void
         */
        public function handle(): void {
            // TODO:
    
            echo "done\n";
    
            $this->delete();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    如需传递自定义参数至该 Job 类,只需在 __construct 方法中添加形参相应,并传递至成员变量,例如:

    
    
    namespace App\Jobs;
    
    class WeeklyStatisticsJob extends Job {
    
        private int $supplierId;
        private string $beginDate;
        private string $endDate;
    
        public function __construct(int $supplier_id, string $begin_date, string $end_date) {
            $this->supplierId = $supplier_id;
            $this->beginDate = $begin_date;
            $this->endDate= $end_date;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    TODO: 部分为实际业务代码,例如调用服务类实现统计并存储于数据库中。

    应用消息队列

    回到 App\Console\Kernel 类,将消息队列类实例化进 job 方法即可:

    protected function schedule(Schedule $schedule): void {
        $schedule->job(new WeeklyStatisticsJob(1, '2023-11-13', '2023-11-19'))
            ->withoutOverlapping()
            ->timezone('Asia/Shanghai')
            ->weeklyOn([1], '03:00');
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注意,我们为了将其与已有消息队列进行区分,应对其指定单独的队列名称。同样,如果需要单独指定消息队列的连接(使用 databasesqs 等),还需指定连接名。

    所以我们应当修改为:

    protected function schedule(Schedule $schedule): void {
        $schedule->job(
            new WeeklyStatisticsJob(1, '2023-11-13', '2023-11-19'),
            'weekly_calc_statistics',  // 建议指定队列名称,如未指定,默认为 'default'
            'redis'                    // 默认使用 redis 时,此处可忽略
        )
            ->withoutOverlapping()
            ->timezone('Asia/Shanghai')
            ->weeklyOn([1], '03:00');
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    至此,我们的周期任务就已编写完成,但对于测试来说,周期过于漫长,我们可以将 每周一凌晨三点 修改为每分钟,或者每 5-10 分钟进行测试。

    即,将 weeklyOn([1], '03:00') 修改为 everyMinute()everyFiveMinute() 等方法。

    运行测试

    我们首先应当运行上方编写的队列监听:weekly_calc_statistics

    在项目根目录中执行下方命令:

    # 如未指定队列名,可忽略 queue 参数
    php artisan queue:work --queue=weekly_calc_statistics
    
    • 1
    • 2

    随后在 另一 命令窗口中执行:

    php artisan schedule:work
    
    • 1

    稍等片刻,周期任务将生产一条消息队列放入 redis 中,随后可在消息队列命令窗口中看到该队列被消费提示。

  • 相关阅读:
    Linux系统Ubuntu以非root用户身份操作Docker的方法
    《操作系统导论》之并发问题
    故障管理:谈谈我对故障的理解
    主流接口测试框架对比
    京东数据分析软件(京东平台数据分析):2023年Q3扫地机器人行业消费报告
    Vue3基础知识-1
    MSG企业行·AI+医疗专场成功举办!!昇思MindSpore助力智慧医疗深度发展!
    [Codeforces] games (R1600) Part.1
    数据结构——新手村级二叉树讲解
    扩展翡蜀定理问题
  • 原文地址:https://blog.csdn.net/maxsky/article/details/134544546