首页 PHP 正文
151

Task Manager Script

  • yiqingpeng
  • 2019-04-26
  • 0
  •  
<?php
date_default_timezone_set('GMT');
ini_set('memory_limit', -1);

if (PHP_SAPI !== 'cli') {
    header('Status: 400');
    exit('Invalid access');
}

function println($msg, $color = null, $eol = true) {
    $colorMap = [
        'white' => "\e[0;97m", 
        'red' => "\e[0;31m", 
        'green' => "\e[0;32m", 
        'blue' => "\e[0;34m", 
        'yellow' => "\e[0;33m", 
        'magenta' => "\e[0;35m", 
        'cyan' => "\e[0;36m", 
        'black' => "\e[0;30m", 
    ];
    $colorEnd = "";
    if (!empty($colorMap[$color])) {
        echo $colorMap[$color];
        $colorEnd = "\e[0m";
    }
    echo $msg, $colorEnd;
    if ($eol) {
        echo PHP_EOL;
    }
}

define('CACHE_DIR', '/var/tmp/cache/');
!is_dir(CACHE_DIR) && @mkdir(CACHE_DIR);
if (is_dir('/ebs1')) {
    define('LOGGING_DIR', '/ebs1/rackspace/');
} else {
    define('LOGGING_DIR', '/var/log/rackspace/');
}
!is_dir(LOGGING_DIR) && @mkdir(LOGGING_DIR);

class Task{
    const LOCKED_FLAG = 1;
    const UNLOCKED_FLAG = 0;
    private $name;
    private $command;
    private $lockfile;
    private $proccessfile;
    
    public function __construct($name,  $command){
        if (empty($name) || empty($command)) {
            throw new \Exception('Parameters for counstruct required, but not given.');
        }
        $this->name = $name;
        $this->command = escapeshellcmd($command);
        $this->lockfile = CACHE_DIR . $name . '.lock';
        $this->proccessfile = CACHE_DIR . $name . '_last_item';
    }
    
    public function __get($prop){
        if (in_array($prop, ['name', 'command'])) {
            return $this->$prop;
        }
    }
    
    public function __toString(){
        return $this->name;
    }
    
    public function __invoke($param){
        switch ($param) {
            case 'r':
                return $this->start();
            case 's':
                return $this->stop();
            case 'l':
                return $this->lock();
            case 'u':
                return $this->unlock();
            case 'i':
                return $this->reset();
            case 'w':
                return $this->watch();
            case 'v':
                return $this->view();
            case 'k':
                $v = `cat '{$this->lockfile}'`;
                println($v);
                return $v;
        }
    }
    
    public function reset(){
        $this->unlock();
        file_put_contents($this->proccessfile, '0');
        $rmlog = 'rm -f ' . LOGGING_DIR  . $this->name . '*.log';
        exec($rmlog);
    }
    
    public function isLocked(){
        return @file_get_contents($this->lockfile) == static::LOCKED_FLAG;
    }
    
    public function unlock(){
        @file_put_contents($this->lockfile, static::UNLOCKED_FLAG);
        return $this;
    }
    
    public function lock(){
        @file_put_contents($this->lockfile, static::LOCKED_FLAG);
        return $this;
    }
    
    public function start($force = false){
        if ($this->isLocked()) {
            println(sprintf("Task [%s] start failed as locked.", $this->name), 'red');
            return false;
        }
        if ($force) {
            $this->stop();
        } else {
            if ($this->lookupCmd(true)) {
                println(sprintf('Task [%s] start failed as on running.', $this->name), "red");
                return false;
            }
        }
        $pid = $this->execAsync($this->command);
        if ($pid) {
            println(sprintf('Task [%s](pid=%s) start successfully.', $this->name, $pid), "green");
        }
        return $pid;
    }
    
    public function execAsync($cmd, $workDir = null){
        $shell = (is_dir($workDir) ? "cd $workDir;" : "") . "nohup $cmd >>" .LOGGING_DIR . "{$this->name}.log 2>&1 & echo $!";
        exec($shell, $output);
        return @$output[0];// return Pid
    }
    
    public function restart(){
        return $this->start(true);
    }
    
    public function stop($pid = null){
        $pids = $this->lookupCmd(true);
        foreach ($pids as $pid) {
            println('Stopped following command:', "magenta");
            $output = $this->killCmdByPID($pid);
            println(implode(PHP_EOL, $output));
        }
        return $this;
    }
    
    private function killCmdByPID($pid){
        $pid = (int)$pid;
        if (!$pid) return [];
        exec('ps -fp ' . $pid, $output);
        exec('kill -9 ' . $pid, $none);
        return $output;
    }
    
    public function view() {
        $output = $this->lookupCmd();
        println(implode(PHP_EOL, $output));
        return $this;
    }
    
    public function lookupCmd($onlyPid = false){
        $shell = 'ps -ef|grep \'' . $this->command .'\'|grep -v grep';
        if ($onlyPid) {
            $shell .= '|awk \'{print $2}\'';
        }
        exec($shell, $output);
        return $output;
    }
    
    public function watch(){
        println(@file_get_contents($this->proccessfile));
        return $this;
    }
    
    public function monitor(){
        $pid = $this->lookupCmd(true);
        if (empty($pid)) {
            $this->onLost();
        }
        return $this;
    }
    
    private function onLost(){
        $this->start();
    }
    
}

class TaskManager{
    private $tasks = [];
    
    public function addTask($name, $command = null){
        if (is_array($name)) {
            $this->tasks = array_merge($this->tasks, $name);
        } else if (is_string($name) || is_int($name)) {
            $this->tasks[$name] = is_callable($command) ? $command($name) : $command;
        }
        return $this;
    }
    
    public function __call($method,  $arguments){
        if (substr($method, -3) == 'All') {
            return $this->callMethodForEveryTask(substr($method, 0, -3), $arguments);
        } else if (in_array($method,  get_class_methods('Task')) && !empty($arguments)) {
            return $this->callMethodOfTask($arguments[0], $method, array_splice($arguments, 1));
        }
    }
    
    private function callMethodOfTask($taskName,  $method, $arguments) {
        if (!$this->valid($taskName)) {
            println('Task is not existed');
            return false;
        }
        $taskInst = $this->getTask($taskName);
        return call_user_func_array([$taskInst, $method], $arguments);
    }
    
    private function callMethodForEveryTask($method, $arguments) {
        foreach ($this->tasks as $task => $cmd) {
            $this->callMethodOfTask($task, $method, $arguments);
        }
    }

    private function valid($taskName){
        if (is_numeric($taskName)) {
            return isset(array_keys($this->tasks)[$taskName]);
        } else {
            return isset($this->tasks[$taskName]);
        }
    }
    
    public function dispatchMethod($taskName, $method, $arguments = null){
        if ($taskName) {
            return call_user_func_array([$this, $method], array_merge([$taskName], (array)$arguments));
        } else {
            return call_user_func_array([$this, $method . 'All'], array_merge([$taskName], (array)$arguments));
        }
    }

    public function __toString(){
        return var_export($this->tasks, true);
    }
    
    public function getTask($taskName){
        if (is_numeric($taskName)) {
            $taskName = array_keys($this->tasks)[$taskName];
        } 
        return new Task($taskName, $this->tasks[$taskName]);
    }
}

$options = getopt('c::n::v::V::');

function initTaskManager(){
    $taskManager = new TaskManager();
    $dir = realpath(__DIR__);
    $nameFmt = 'rackspace_transfer_%d';
    $cmdFmt = 'php ' . $dir . '/rackspace_transfer.php -n%s -p%d,%d';
    
    $autoCreateTasks = function() use ($nameFmt, $cmdFmt){
        $pow = 10 ** 5;
        $step = $pow - 1;
        $tasks = [];
        for ($i = 0; $i < 9 ; $i++) {
            $name = sprintf($nameFmt, $i * $pow);
            $cmd = sprintf($cmdFmt, $name, $i * $pow, $i * $pow + $step);
            $tasks[$name] = $cmd;
            
        }
        return $tasks;
    };
    $tasks = $autoCreateTasks();
    $taskManager->addTask($tasks);

    return $taskManager;
}


$taskManager = initTaskManager();
$taskName = !isset($options['n']) ? '' : $options['n'];
if ($taskName && isset($options['v'])) {
    println($taskManager->getTask($taskName));
    exit;
}
if ($taskName && isset($options['V'])) {
    $task = $taskManager->getTask($taskName);
    $task($options['V']);
    exit;
}
switch ($options['c']) {
    case 'start':
    case 'stop':
    case 'monitor':
    case 'view':
    case 'watch':
    case 'restart':
    case 'reset':
    case 'lock':
    case 'unlock':
        $taskManager->dispatchMethod($taskName, $options['c']);
        break;
    default:
        echo $taskManager, "\n";
        break;
}

正在加载评论...