计划任务的执行时间和频率放到数据库中,实现自动化

客户希望建个自动报告发送表 autoSendReport
字段:报告 ID,开始日期,结束日期,发送时间,发送频率 (1 每天,2 每周,3 每月),收件人
需求:设置好后,报告就按设置的时间发送到收件人里
举例:2021-4-20 到 2021-4-30 每天 10:00 发送报告 1 到收件人 xx@qq.com

我的想法,再建立一个发送记录表 sendReportRecord,字段:发送的报告 ID,发送状态和发生时间,避免重复发送
我需要设置一个计划任务频率设置到每 10 分钟检测?
另外一个问题,如果发送频率改变了怎么办

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
最佳答案

写一个监听 redis key 过期任务 ,每次创建任务、计算第一次发送时间距离现在多久,设置 key 的过期时间。 每次监听到了,就去数据库查询发送任务、执行发送任务、然后计算下一次发送时间。

3年前 评论
tiansai 3年前
讨论数量: 7

弄个定时任务,频率就是你需求所要的最小频率为单位,比如,你上面要求的最小粒度是每天,那你的定时任务就设置为每天执行一次,然后 PHP 脚本里面,通过代码判断你客户当前设置的频率,如果是每天,就执行。如果设置的是每周一,那你判断今天试不是周一,是就执行,不是就退出,以此类推

3年前 评论

crontab + 任务调度,每分钟一次,然后通过 SQL 检索条件应该就可以了吧。。

发送记录这个应该有,记录成功失败,发送事件,失败重试等。

3年前 评论

增加一个下次执行时间,频率变化后计算下次执行时间,定时任务频率根据你业务承载自行变化,每次只查询下次执行时间小于当前时间的!

3年前 评论

按照第一性原则,根据生活经验,别人交代你的事情,你是怎么避免忘记的从而执行的?

3年前 评论

写一个监听 redis key 过期任务 ,每次创建任务、计算第一次发送时间距离现在多久,设置 key 的过期时间。 每次监听到了,就去数据库查询发送任务、执行发送任务、然后计算下一次发送时间。

3年前 评论
tiansai 3年前

楼上的兄弟们说的都对,我没啥可补充的了。个人觉得一楼的方案就可以了,不用弄的很复杂。

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    protected function schedule(Schedule $schedule)
    {
        // $schedule->command('inspire')->hourly();
        $schedule->call(function(){
           $now = \Carbon\Carbon::now();
           $nowStr = $now->toDateTimeString();
           \App\Models\AutoSendReport::where('开始日期', '<=', $nowStr)
            ->where('结束日期', '>=', $nowStr)
            ->get()
            ->map(function($plan)use($now){
                $shouldSend = false;
                switch ($plan->频率) {
                    case '每天':
                        // 每天上午 10 点发送
                        $shouldSend = true;
                        break;

                    case '每周':
                        // 每周一发送
                        $shouldSend = $now->isMonday();
                        break;

                    case '每月':
                        // 每月第一天发送
                        $shouldSend = $now->day == 1;
                        break;
                }
                if($shouldSend){
                    \Mail::to($plan['收件人邮箱'], $plan['收件人姓名'])->send(new \Illuminate\Mail\Mailable());
                }
            });
        })
        ->timezone('Asia/Shanghai')
        // 每天上午 10 点执行一次
        ->dailyAt('10:00');
    }
}

详细的频率设置参考 文档

3年前 评论
LiamHao (作者) 3年前
xiaohuasheng 3年前