qq497012571 2019-02-20 16:48:05 4571次浏览 1条评论 8 1 0

正对解决使用YII2构建一个定时任务管理后台一些问题的后续

解决多服务器集群下, 同一个任务,同一时间在多个服务器下, 重复执行的问题, 也解决了任务耗时较长, 没跑完又发起一个新的定时任务问题,导致资源无法释放,服务器卡死

巧用乐观锁

  1. crontab表改动

crontab表的status字段, 值代表的意思改动为: 0正常 1运行中 2任务报错 多了一个*运行中*的状态! 注意!!

实现原理: 当任务判断为可以运行时就把就把定时任务状态调用update方法,改为1, 成功rue,失败false, 只有true的任务才能执行,反之跳过

  • 注意事项, 很重要

说一下自己遇到的一些坑, 例如服务器断电或者挂了, 那么就会导致一些进行中的任务状态没改成正常, 所以,断电了就要把定时任务的状态都恢复成正常

  1. 代码改动 CrontabController.php
  • 定义一个类的全局常量
class CrontabController extends Controller
{

    const WAIT_SYNC_TIME = 5;
    .....
    
  • 修改executeTask方法代码
private function executeTask(array $tasks)
{
        if (empty($tasks)) {
            return;
        }

        shuffle($tasks);

        $pool = [];
        $startExectime = $this->getCurrentTime();
        $pid = getmypid();
        $startDate = date('Y-m-d H:i:s');

        foreach ($tasks as $k => $task) {
            // 乐观锁, 上锁. 防止同一任务,重复执行, 
            $task->status = 1;
            $isOk = $task->update(false); 
            if ($isOk) {
                Yii::info("pid[$pid] 定时任务启动: {$task->name}, route: {$task->route}");
                $pool[$k] = proc_open("php yii $task->route", [], $pipe);
            }
        }

        // 防止同一任务,在多个机器上,重复执行
        sleep(self::WAIT_SYNC_TIME);

        // 回收子进程
        while (count($pool)) {
            foreach ($pool as $i => $result) {
                $etat = proc_get_status($result);
                if($etat['running'] == FALSE) {
                    proc_close($result);
                    unset($pool[$i]);

                    $tasks[$i]->exectime     = round($this->getCurrentTime() - $startExectime - self::WAIT_SYNC_TIME, 2);
                    $tasks[$i]->last_rundate = $startDate;
                    $tasks[$i]->next_rundate = $tasks[$i]->getNextRunDate();
                    $tasks[$i]->status       = '0';

                    // 任务出错
                    if ($etat['exitcode'] !== ExitCode::OK) {
                        $tasks[$i]->status = 2;
                    }
                    $tasks[$i]->save(false);
                }
            }
        }

}
觉得很赞
  • 评论于 2019-02-20 16:49 举报

    WAIT_SYNC_TIME 常量是有用的, 最好保证所有服务器的服务器时间要一致

您需要登录后才可以评论。登录 | 立即注册