侧边栏壁纸
博主昵称
梦之中小俊

以前高中时,羡慕大学考试只要及格就行;现在大学了,怀念高中考试及不及格都行??

PHP

thinkphp6+swoole实现crontab项目定时任务

梦之中小俊
2023-06-25 / 0 评论 / 318 阅读 / 推送成功!

背景

之前做定时任务,都是通过linux的crontab来实现,但是定时任务多了,就不好管理。一个是是定时的备注不好写,另一个是定时日志的结果没法存入数据库。

需求

1、按crontab的格式设置定时任务

2、执行结果存入数据库,包括执行结果,执行时间

3、秒级的定时
安装依赖
composer require dragonmantank/cron-expression
代码实现
1、添加一个自定义指令 Task

php think make:command Task task
2、在config/console.php中注册该指令

// 指令定义

'commands' => [

'task' => \app\command\Task::class,

],



setName('task')
            ->setDescription('the task command');
    }
 
    protected function execute(Input $input, Output $output)
    {
        $output->writeln('Execute start!'.Date('Y-m-d H:i:s'));
        run(function () use($output) {
            $time = time();
 
            //筛选未过期且未完成的任务
            $crontabList = Db::name('system_task')->where('status', '=', '1')->order('weigh DESC,id DESC')->select();
 
            // 准备需要执行的crontab
            $out_crontab_arr = [];
            $max_crontab_arr = [];
            $exe_crontab_arr = [];
 
            foreach ($crontabList as $key => $crontab) {
                if ($time < $crontab['begintime']) {
                    $output->writeln('任务未开始');
                    continue;
                }
                if ($crontab['maximums'] && $crontab['executes'] > $crontab['maximums']) {
                    //任务已超过最大执行次数
                    $output->writeln('任务已超过最大执行次数');
                    array_push($max_crontab_arr,$crontab);
                } else {
                    if ($crontab['endtime'] > 0 && $time > $crontab['endtime']) {
                        //任务已过期
                        $output->writeln('任务已过期');
                        array_push($out_crontab_arr,$crontab);
                    } else {
                        //重复执行
                        //如果未到执行时间则继续循环
                        $cron = CronExpression::factory($crontab['schedule']);
                        if (!$cron->isDue(date("YmdHi", $time)) || date("YmdHi", $time) === date("YmdHi", $crontab['executetime'])) {
                            $output->writeln('未到执行时间则继续循环');
                            continue;
                        }else{
                            array_push($exe_crontab_arr,$crontab);
                        }
                    }
                }
            }
            if($out_crontab_arr){
                $out_id_arr = array_column($out_crontab_arr,'id');
                Db::name('system_task')->where('id','in',$out_id_arr)->update(['status'=>3]);
            }
            if($max_crontab_arr){
                $max_id_arr = array_column($max_crontab_arr,'id');
                Db::name('system_task')->where('id','in',$max_id_arr)->update(['status'=>2]);
            }
            if($exe_crontab_arr){
                $chan = new Coroutine\Channel(count($exe_crontab_arr));
                $port = Config::get('swoole.server.port');
 
 
                foreach($exe_crontab_arr as $key => $crontab){
                    $log = [
                        'crontab_id'   => $crontab['id'],
                        'content'      => '',
                        'status'       => '', // 暂时不知道
                        'create_datetime' => Date('Y-m-d H:i:s')
                    ];
                    $crontab['log_id'] = Db::name("system_task_log")->insertGetId($log);
                    // 
                    go(function () use ($chan,$crontab,$port) {
                        $curl = new Curl();
                        $curl->setOpt(CURLOPT_TIMEOUT,50);
                        $curl->get('http://0.0.0.0:'.$port.$crontab['content']);
                        // $res = $curl->response;
                        $curl->close();
                        if(is_string($curl->response)){
                            $chan->push([$crontab['log_id'] => ['msg'=>'执行完毕','data'=>$curl->response,'update_time'=>time()]]);
                        }else{
                            $chan->push([$crontab['log_id'] => ['msg'=>'执行超时或异常','data'=>$curl->response,'update_time'=>time()]]);
                        }
                        
                    });
                }
                $result = [];
                $log_res_arr = [];
                for ($i = 0; $i < count($exe_crontab_arr); $i++)
                {
                    $result += $chan->pop();
                }
                
                foreach($result as $log_id => $res_data){
                    $update_datetime = Date('Y-m-d H:i:s',$res_data['update_time']);
                    if($res_data['msg'] == '执行完毕'){
                        $res = json_decode($res_data['data'],true);
                        if(isset($res['code'] ) && $res['code'] == 200){
                            array_push($log_res_arr,['id'=>$log_id,'status'=>'success','content'=>'成功','update_datetime'=>$update_datetime]);
                        }else{
                            $fail_msg = isset($res['msg']) ? $res['msg'] : '无msg返回,未知错误';
                            array_push($log_res_arr,['id'=>$log_id,'status'=>'failure','content'=>$fail_msg,'update_datetime'=>$update_datetime]);
                        }
                    }else{
                        array_push($log_res_arr,['id'=>$log_id,'status'=>'failure','content'=>$res_data['msg'],'update_datetime'=>$update_datetime]);
                    }
                }
                $model = new SystemTaskLog();
                $model->saveAll($log_res_arr);
            }
        });
        // 指令输出
        $output->writeln('Execute completed!'.Date('Y-m-d H:i:s'));
    }
}

 

在linux中设置该定时

crontab -e

* * * * * /www/server/php/73/bin/php /www/wwwroot/abc.com/think task  >> /www/server/cron/abc.com.log 2>&1

 

设置定时任务

查看定时结果

秒级定时

因为我们用的 cron-expression 是分钟级的,如果执行到秒级,其实是做不到的。

目前是任务里做一分钟的分割,以下做了简单粗暴的处理,当然如果项目里面有很多秒级任务,建议自己优化,或者其他方案

    public function time20s()
    {
 
        $this->doOnce();
        //在指定的时间后执行函数,20秒后执行
        \Swoole\Timer::after(20000, function() use ($url) {
            $this->doOnce();
            \Swoole\Timer::after(20000, function() use ($url) {
                  $this->doOnce();
            });
        });
 
    }

 

注意点

1、设置50秒超时,防止任务执行过长,所有任务的执行结果都得不到

本文共 个字数,平均阅读时长 ≈ 分钟,您已阅读:0时0分0秒。
3

打赏

评论 (0)

OωO
  • ::(呵呵)
  • ::(哈哈)
  • ::(吐舌)
  • ::(太开心)
  • ::(笑眼)
  • ::(花心)
  • ::(小乖)
  • ::(乖)
  • ::(捂嘴笑)
  • ::(滑稽)
  • ::(你懂的)
  • ::(不高兴)
  • ::(怒)
  • ::(汗)
  • ::(黑线)
  • ::(泪)
  • ::(真棒)
  • ::(喷)
  • ::(惊哭)
  • ::(阴险)
  • ::(鄙视)
  • ::(酷)
  • ::(啊)
  • ::(狂汗)
  • ::(what)
  • ::(疑问)
  • ::(酸爽)
  • ::(呀咩爹)
  • ::(委屈)
  • ::(惊讶)
  • ::(睡觉)
  • ::(笑尿)
  • ::(挖鼻)
  • ::(吐)
  • ::(犀利)
  • ::(小红脸)
  • ::(懒得理)
  • ::(勉强)
  • ::(爱心)
  • ::(心碎)
  • ::(玫瑰)
  • ::(礼物)
  • ::(彩虹)
  • ::(太阳)
  • ::(星星月亮)
  • ::(钱币)
  • ::(茶杯)
  • ::(蛋糕)
  • ::(大拇指)
  • ::(胜利)
  • ::(haha)
  • ::(OK)
  • ::(沙发)
  • ::(手纸)
  • ::(香蕉)
  • ::(便便)
  • ::(药丸)
  • ::(红领巾)
  • ::(蜡烛)
  • ::(音乐)
  • ::(灯泡)
  • ::(开心)
  • ::(钱)
  • ::(咦)
  • ::(呼)
  • ::(冷)
  • ::(生气)
  • ::(弱)
  • ::(狗头)
泡泡
阿鲁
颜文字
取消
  1. 头像
    6767 Lv.1
    iPhone · Safari
    沙发

    画图

    回复
  2. 头像
    6767 Lv.1
    Windows 10 · Google Chrome
    板凳

    表情

    回复
  3. 头像
    透露 Lv.2
    Android · QQ Browser
    第30楼

    649494848

    回复