| 
...
 | 
...
 | 
@@ -3,35 +3,96 @@ | 
| 
 | 
 | 
 include_once "../vendor/autoload.php";
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 // 这里试试不用多进程模式,用多协程模式
 | 
| 
 | 
 | 
 function start(){
 | 
| 
 | 
 | 
     _echo('启动邮件群发任务');
 | 
| 
 | 
 | 
     // 删除key
 | 
| 
 | 
 | 
     redis()->delete('send_job_is_stop');
 | 
| 
 | 
 | 
     // 开启协程
 | 
| 
 | 
 | 
     \Co\run(function (){
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         $cNum = 0;//协程运行的数量
 | 
| 
 | 
 | 
         $maxRunNum = 500;
 | 
| 
 | 
 | 
         while ($maxRunNum){
 | 
| 
 | 
 | 
             $maxRunNum--;
 | 
| 
 | 
 | 
             if(!$maxRunNum){
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 class SendJob {
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public $cnum = 0;
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * 是否停止
 | 
| 
 | 
 | 
      * @return bool
 | 
| 
 | 
 | 
      * @author:dc
 | 
| 
 | 
 | 
      * @time 2024/4/10 9:12
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     private function isStop(){
 | 
| 
 | 
 | 
         return redis()->get('send_job_is_stop') == 'stop';
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * 休眠
 | 
| 
 | 
 | 
      * @param float $sleep
 | 
| 
 | 
 | 
      * @return bool
 | 
| 
 | 
 | 
      * @author:dc
 | 
| 
 | 
 | 
      * @time 2024/4/10 9:12
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     private function s_sleep(float $sleep):bool {
 | 
| 
 | 
 | 
         if($sleep > 0){
 | 
| 
 | 
 | 
             $t = microtime(1);
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             while (!$this->isStop()){
 | 
| 
 | 
 | 
                 co::sleep(0.1);
 | 
| 
 | 
 | 
                 if($sleep - (microtime(1)-$t) <= 0){
 | 
| 
 | 
 | 
                     break;
 | 
| 
 | 
 | 
                 }
 | 
| 
 | 
 | 
             try {
 | 
| 
 | 
 | 
             }
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
         return true;
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     public function start(){
 | 
| 
 | 
 | 
         _echo('启动邮件群发任务 '.getmypid());
 | 
| 
 | 
 | 
         // 删除key
 | 
| 
 | 
 | 
         redis()->delete('send_job_is_stop');
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         while (1){
 | 
| 
 | 
 | 
             // 是否要停止
 | 
| 
 | 
 | 
                 if(redis()->get('send_job_is_stop')=='stop'){
 | 
| 
 | 
 | 
             if($this->isStop()){
 | 
| 
 | 
 | 
                 break;
 | 
| 
 | 
 | 
             }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             $lists  =   db()->all(\Model\sendJobsSql::sendList(500));
 | 
| 
 | 
 | 
             $lists = $lists?$lists:[];
 | 
| 
 | 
 | 
                 // 循环
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             if($lists){
 | 
| 
 | 
 | 
                 foreach ($lists as $list){
 | 
| 
 | 
 | 
                     $this->go_($list);
 | 
| 
 | 
 | 
                 }
 | 
| 
 | 
 | 
             }else{
 | 
| 
 | 
 | 
                 // 休眠30秒
 | 
| 
 | 
 | 
                 $this->s_sleep(30);
 | 
| 
 | 
 | 
             }
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         // 这个是等待所有协程退出
 | 
| 
 | 
 | 
         while (true){
 | 
| 
 | 
 | 
             _echo('等待协程退出...');
 | 
| 
 | 
 | 
             if(!$this->cnum){
 | 
| 
 | 
 | 
                 break;
 | 
| 
 | 
 | 
             }
 | 
| 
 | 
 | 
             co::sleep(1);
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     /**
 | 
| 
 | 
 | 
      * @param $list
 | 
| 
 | 
 | 
      * @throws \Lib\Err
 | 
| 
 | 
 | 
      * @throws \PHPMailer\PHPMailer\Exception
 | 
| 
 | 
 | 
      * @author:dc
 | 
| 
 | 
 | 
      * @time 2024/4/10 9:25
 | 
| 
 | 
 | 
      */
 | 
| 
 | 
 | 
     public function go_($list){
 | 
| 
 | 
 | 
         // 占用 id
 | 
| 
 | 
 | 
                     if(redis()->add('send_job_run_id_'.$list['id'],$list['id'],3600)){
 | 
| 
 | 
 | 
                         go(function ($data) use (&$cNum){
 | 
| 
 | 
 | 
                             $cNum++; // 协程数+1
 | 
| 
 | 
 | 
         if(redis()->add('send_job_run_id_'.$list['id'],$list['id'],600)){
 | 
| 
 | 
 | 
             go(function ($data) {
 | 
| 
 | 
 | 
                 _echo('正在执行任务 '.$data['id']);
 | 
| 
 | 
 | 
                 $this->cnum++; // 协程数+1
 | 
| 
 | 
 | 
                 // 表单数据
 | 
| 
 | 
 | 
                 $data['maildata'] = json_decode($data['maildata'],true);
 | 
| 
 | 
 | 
                 // 查询邮箱
 | 
| 
...
 | 
...
 | 
@@ -42,6 +103,9 @@ function start(){ | 
| 
 | 
 | 
                 if($data['maildata']['massSuit']??0){
 | 
| 
 | 
 | 
                     $tos    =   $data['maildata']['tos'];
 | 
| 
 | 
 | 
                     foreach ($tos as $to){
 | 
| 
 | 
 | 
                         _echo('正在执行任务 发送邮件 '.$to['email']);
 | 
| 
 | 
 | 
                         // 续时间
 | 
| 
 | 
 | 
                         redis()->set('send_job_run_id_'.$data['id'],$data['id'],600);
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                         // 是否暂停
 | 
| 
 | 
 | 
                         $dst = db()->first(\Model\sendJobsSql::isStatus($data['id']));
 | 
| 
...
 | 
...
 | 
@@ -76,12 +140,12 @@ function start(){ | 
| 
 | 
 | 
                                 $block = false;
 | 
| 
 | 
 | 
                                 while (true){
 | 
| 
 | 
 | 
                                     // 没5秒循环一次
 | 
| 
 | 
 | 
                                                 if(redis()->get('send_job_is_stop')=='stop'){
 | 
| 
 | 
 | 
                                     if($this->isStop()){
 | 
| 
 | 
 | 
                                         $block = true;
 | 
| 
 | 
 | 
                                         break;
 | 
| 
 | 
 | 
                                     }
 | 
| 
 | 
 | 
                                     $time-=5;
 | 
| 
 | 
 | 
                                                 co::sleep(5);
 | 
| 
 | 
 | 
                                     $this->s_sleep(5);
 | 
| 
 | 
 | 
                                     // 执行下一次了
 | 
| 
 | 
 | 
                                     if (!$time){
 | 
| 
 | 
 | 
                                         $block = true;
 | 
| 
...
 | 
...
 | 
@@ -97,7 +161,8 @@ function start(){ | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                             }else{
 | 
| 
 | 
 | 
                 }
 | 
| 
 | 
 | 
                 else{
 | 
| 
 | 
 | 
                     $result = \Lib\Mail\MailFun::sendEmail($data['maildata'],$email);
 | 
| 
 | 
 | 
                     // 更新状态
 | 
| 
 | 
 | 
                     db()->update(\Model\sendJobsSql::$table,[
 | 
| 
...
 | 
...
 | 
@@ -115,8 +180,8 @@ function start(){ | 
| 
 | 
 | 
                 }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                 // 协程结束后
 | 
| 
 | 
 | 
                             co::defer(function ($id) use(&$cNum,$data){
 | 
| 
 | 
 | 
                                 $cNum--;
 | 
| 
 | 
 | 
                 co::defer(function ($id) use($data){
 | 
| 
 | 
 | 
                     $this->cnum--;
 | 
| 
 | 
 | 
                     // 验证是否完成
 | 
| 
 | 
 | 
                     if($data['maildata']['massSuit']??0){
 | 
| 
 | 
 | 
                         $total = db()->first(\Model\sendJobStatusSql::countSum($data['id']));
 | 
| 
...
 | 
...
 | 
@@ -147,41 +212,33 @@ function start(){ | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             }catch (Throwable $e){
 | 
| 
 | 
 | 
                 logs($e->getMessage().$e->getTraceAsString());
 | 
| 
 | 
 | 
             }
 | 
| 
 | 
 | 
 }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             \Lib\Log::getInstance()->write();
 | 
| 
 | 
 | 
             // 暂停5秒
 | 
| 
 | 
 | 
             co::sleep(5);
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         // 这个是等待所有协程退出
 | 
| 
 | 
 | 
         while (true){
 | 
| 
 | 
 | 
             if(!$cNum){
 | 
| 
 | 
 | 
                 break;
 | 
| 
 | 
 | 
             }
 | 
| 
 | 
 | 
             co::sleep(0.5);
 | 
| 
 | 
 | 
         }
 | 
| 
 | 
 | 
 $ps = "ps -ef | grep \"send_job.php start\" | grep -v grep | wc -l";
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 switch ($argv[1]??0){
 | 
| 
 | 
 | 
     case 'start':{
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
     });
 | 
| 
 | 
 | 
 }
 | 
| 
 | 
 | 
         // 开启协程
 | 
| 
 | 
 | 
         \Co\run(function (){
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             $handler = function ($signal){
 | 
| 
 | 
 | 
                 // 可以处理其他程序
 | 
| 
 | 
 | 
                 redis()->set('send_job_is_stop','stop');
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
                 _echo('收到退出信号 '.$signal);
 | 
| 
 | 
 | 
             };
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             \Swoole\Process::signal(SIGTERM,$handler);
 | 
| 
 | 
 | 
             \Swoole\Process::signal(SIGINT,$handler);
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
             (new SendJob)->start();
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 $ps = "ps -ef | grep \"send_job.php start\" | grep -v grep | wc -l";
 | 
| 
 | 
 | 
             _echo('进程已退出');
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
         });
 | 
| 
 | 
 | 
 
 | 
| 
 | 
 | 
 switch ($argv[1]??0){
 | 
| 
 | 
 | 
     case 'start':{
 | 
| 
 | 
 | 
 //        $num = exec($ps);
 | 
| 
 | 
 | 
 //        if($num){
 | 
| 
 | 
 | 
 //            echo '正则运行,请勿重复运行';
 | 
| 
 | 
 | 
 //        }else{
 | 
| 
 | 
 | 
             start();
 | 
| 
 | 
 | 
 //        }
 | 
| 
 | 
 | 
         break;
 | 
| 
 | 
 | 
     }
 | 
| 
 | 
 | 
     case 'stop':{
 | 
...
 | 
...
 | 
 |