一个批量结算任务的demo

来源:互联网 发布:tensorflow翻译 编辑:程序博客网 时间:2024/05/23 20:42
<?phpclass BaseBatchSettleCommand extends CConsoleCommand{    protected $maxProcessNum = 5;    protected $pid=0;    protected $numFlag = 50000;    protected $loopNum = 1000;    protected $start_id=0;    protected $end_id=0;    protected $is_child = false;    protected $base_args = [];    protected $pre_process_list=[];    protected $process_start_time = 0;    protected $process=null;    protected $success_count=0;    protected $fail_count=0;    protected $discount=0;    protected function getBaseArg($arg){        if(isset($this->base_args[$arg])){            return $this->base_args[$arg];        }        $class = get_called_class();        $methods = get_class_methods($class);        if(in_array('get_'.$arg,$methods)){            $ret = call_user_func([$this,"get_".$arg]);            $this->setBaseArg($arg,$ret);            return $ret;        }        return [];    }    public function setBaseArg($arg,$value){        $this->base_args[$arg]=$value;    }    protected function output($str) {        $content =  date('Y-m-d H:i:s') . '  pid:' . $this->pid . ', ' .' command:'.$this->getCommandName().' start:'.$this->start_id.' end:'.$this->end_id.' '. $str . "\n";        echo $content;    }    public function alert($message){        Yii_Log::warning($this->getCommandName().' err:'.$message);    }    protected function getCommandName(){        $class = get_called_class();        $res = substr($class,0,strlen($class)-7);        return $res;    }    /**     * 4个初始化参数     * 1为起始id     * 2为截止id     * 3标志是否为子进程,子进程不会在创建子进程     * 4为其他初始化参数,多个参数用下划线隔离     */    protected function createProcess($start_id,$end_id,$ini) {        $command = $this->getCommandName();        $processNum = $this->getProcessNum();        if(intval($processNum) > $this->maxProcessNum+1){            $this->output('script process num is max');            //$this->alarm('script process num is max');            return false;        }        $cmd = "nohup /usr/work/tool/php/bin/php /usr/work/tool/app/depository/protected/commands/crons.php {$command}  {$start_id} {$end_id} 1 {$ini} 2>&1 >> /usr/work/tool/log/{$command}.log &";        pclose(popen($cmd, "r"));        $this->output('script process: create sub process');        return true;    }    public function getStartId(){        return $this->start_id;    }    public function getEndId(){        return $this->end_id;    }    protected function getList($start,$end){        return [];    }    protected function getSettleNum(){            }    protected function settle($record){    }    protected function processStart($args){    }    protected function processEnd(){    }    protected function getProcessNum(){//        $count = 0;//        $pid_dir = DATA_DIR.'/command_pid/'.$this->getCommandName();//        $list = scandir($pid_dir);//        foreach ($list as $value){//            if(strpos($value,'.pid')!==false){//                $count++;//            }//        }        $rand = rand(100000,500000);        usleep($rand);        $command = $this->getCommandName();        $count = `ps aux|grep -i "crons.php {$command}"|grep -v "grep"|wc -l`;//没有查表或写文件,因为可能有延时        return intval($count);    }    private function _processStart($args){//        $this->writePidFile();        $this->output('process start args:'.json_encode($args));        $process = new ProcessInfo();        $process->start_id = $this->start_id;        $process->end_id = $this->end_id;        $process->status = ProcessInfo::STATUS_CREATE;        $process->is_child = $this->is_child?1:0;        $process->start_time = $this->process_start_time;        $process->snap_date = $this->getSnapDate();        $process->pid = $this->pid;        $process->command = $this->getCommandName();        $process->save();        $this->process = $process;        $this->beforeRun();        $process->status = ProcessInfo::STATUS_RUNNING;        $process->save();        try{            $this->processStart($args);        }catch (Exception $e){            $this->alert($e->getMessage());        }    }    private function _processEnd(){        try{            $this->processEnd();        }catch (Exception $e){            $this->alert($e->getMessage());        }        $this->process->status = ProcessInfo::STATUS_END;        $this->process->success_count = $this->success_count;        $this->process->fail_count = $this->fail_count;        $this->process->discount = $this->discount;        $this->process->end_time = time();        $this->process->save();        if($this->getProcessNum()==1){            $pid_dir = DATA_DIR.'/command_end/';            $file = $this->getCommandName().date('Y-m-d').'.end';            if(!is_dir($pid_dir)){                mkdir($pid_dir);            }            file_put_contents($pid_dir.$file,$this->pid);        }        $this->output('process end');//        $this->deletePidFile();    }//    private function writePidFile(){//        $pid_dir = DATA_DIR.'/command_pid/'.$this->getCommandName();//        $pid_file = $pid_dir.'/'.$this->pid.'.pid';//        if(!is_dir($pid_dir)){//            mkdir($pid_dir);//        }//        file_put_contents($pid_file,$this->pid);//    }//    private function deletePidFile(){//        $pid_dir = DATA_DIR.'/command_pid/'.$this->getCommandName();//        $pid_file = $pid_dir.'/'.$this->pid.'.pid';//        if(file_exists($pid_file)){//            unlink($pid_file);//        }//    }    protected function checkPreProcessEnd(){        if(empty($this->pre_process_list)){            return true;        }        foreach ($this->pre_process_list as $value){            $pid_dir = DATA_DIR.'/command_end/';            $file = $value.date('Y-m-d').'.end';            if(file_exists($pid_dir.$file)){                return true;            }        }        return false;    }    private function beforeRun(){        while (true){            if($this->checkPreProcessEnd()){                return;            }            $this->process->status = ProcessInfo::STATUS_WAITING;            $this->process->save();            sleep(10);        }    }    protected function getIni($args){        $ini = $args[3];        if($ini){            return $ini;        }    }    protected function setIni($arg1_arg2){        $args = explode('_',$arg1_arg2);        return $args;    }    public function run($args){        ini_set('memory_limit', '128M');        /**初始化**/        $this->pid = getmypid();        $this->process_start_time = time();        $start_id = $args[0];        $end_id = $args[1];        $is_child = $args[2]?true:false;        isset($start_id)&&$this->start_id = $start_id;        isset($end_id)&&$this->end_id = $end_id;        isset($this->is_child)&&$this->is_child = $is_child;        $ini = $args[3]?$args[3]:null;        $this->setIni($ini);        /**初始化结束**/        $this->_processStart($args);        if(!isset($start_id)){            $start_id = $this->getStartId();        }        if(!isset($end_id)){            $end_id = $this->getEndId();        }        if($end_id-$start_id>$this->numFlag&&$is_child==false){ //大于10万条数据分子进程加速处理            $max_num = $this->maxProcessNum;            $gap = ceil(($end_id-$start_id+1)/$max_num);            $ini = $this->getIni($args);            for($i=$start_id;$i<=$end_id;$i+=$gap){                $end = $i+$gap-1;                $end>$end_id&&$end = $end_id;                $this->createProcess($i,$end,$ini);//取闭区间            }            $this->_processEnd();            return ;        }        $current = $start_id + $this->loopNum-1;        $current>$end_id&&$current=$end_id;        while ($start_id<=$end_id){            echo 'start,id:'.$start_id."\t 'end,id:$current\t time:".date('Y-m-d H:i:s')."\n";            if(!$this->checkRunTime()){                $this->alert('执行时间过长');                $this->_processEnd();                return;            }            $list = $this->getList($start_id,$current);//取闭区间            $current+=$this->loopNum;            $start_id+=$this->loopNum;            $current>$end_id&&$current=$end_id;            foreach ($list as $value){                try{                    $this->settle($value);                }catch (Exception $e){                    $this->fail_count++;                    $this->alert('error:'.$e->getMessage());                }            }            $this->process->success_count = $this->success_count;            $this->process->fail_count = $this->fail_count;            $this->process->discount = $this->discount;            $this->process->save();        }        $this->_processEnd();    }    protected function checkRunTime(){        return true;        $timestamp = $this->getSnapDate();        if(time()-$timestamp>=85000){//时间跨度不超过1天            return false;        }        return true;    }    protected function getSnapDate(){        $run_date = date('Y-m-d',$this->process_start_time);        $timestamp = strtotime($run_date);        return $timestamp;    }}
原创粉丝点击