Author: Michael Haynes (mike@mjphaynes.com)
Exemple #1
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $host = new Resque\Host();
     $cleaned_hosts = $host->cleanup();
     $worker = new Resque\Worker('*');
     $cleaned_workers = $worker->cleanup();
     $cleaned_hosts = array_merge_recursive($cleaned_hosts, $host->cleanup());
     $cleaned_jobs = Resque\Job::cleanup();
     $this->log('Cleaned hosts: <pop>' . json_encode($cleaned_hosts['hosts']) . '</pop>');
     $this->log('Cleaned workers: <pop>' . json_encode(array_merge($cleaned_hosts['workers'], $cleaned_workers)) . '</pop>');
     $this->log('Cleaned <pop>' . $cleaned_jobs['zombie'] . '</pop> zombie job' . ($cleaned_jobs['zombie'] == 1 ? '' : 's'));
     $this->log('Cleared <pop>' . $cleaned_jobs['processed'] . '</pop> processed job' . ($cleaned_jobs['processed'] == 1 ? '' : 's'));
 }
Exemple #2
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $id = $input->getArgument('id');
     // Do a cleanup
     $worker = new Resque\Worker('*');
     $worker->cleanup();
     if ($id) {
         if (false === ($worker = Resque\Worker::hostWorker($id))) {
             $this->log('There is no worker with id "' . $id . '".', Resque\Logger::ERROR);
             return;
         }
         $workers = array($worker);
     } else {
         $workers = Resque\Worker::hostWorkers();
     }
     if (!count($workers)) {
         $this->log('<warn>There are no workers on this host</warn>');
     }
     $sig = $input->getOption('force') ? 'TERM' : 'QUIT';
     foreach ($workers as $worker) {
         if (posix_kill($worker->getPid(), constant('SIG' . $sig))) {
             $this->log('Worker <pop>' . $worker . '</pop> ' . $sig . ' signal sent.');
         } else {
             $this->log('Worker <pop>' . $worker . '</pop> <error>could not send ' . $sig . ' signal.</error>');
         }
     }
 }
Exemple #3
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $id = $input->getArgument('id');
     // Do a cleanup
     $worker = new Resque\Worker('*');
     $worker->cleanup();
     if ($id) {
         if (false === ($worker = Resque\Worker::hostWorker($id))) {
             $this->log('There is no worker with id "' . $id . '".', Resque\Logger::ERROR);
             return;
         }
         $workers = array($worker);
     } else {
         $workers = Resque\Worker::hostWorkers();
     }
     if (!count($workers)) {
         $this->log('<warn>There are no workers on this host</warn>');
     }
     foreach ($workers as $worker) {
         $packet = $worker->getPacket();
         $job_pid = (int) $packet['job_pid'];
         if ($job_pid and posix_kill($job_pid, 0)) {
             if (posix_kill($job_pid, SIGUSR1)) {
                 $this->log('Worker <pop>' . $worker . '</pop> running job SIGUSR1 signal sent.');
             } else {
                 $this->log('Worker <pop>' . $worker . '</pop> <error>running job SIGUSR1 signal could not be sent.</error>');
             }
         } else {
             $this->log('Worker <pop>' . $worker . '</pop> has no running job.');
         }
     }
 }
Exemple #4
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $workers = Resque\Worker::hostWorkers();
     if (empty($workers)) {
         $this->log('<warn>There are no workers on this host.</warn>');
         return;
     }
     $table = new Resque\Helpers\Table($this);
     $table->setHeaders(array('#', 'Status', 'ID', 'Running for', 'Running job', 'P', 'C', 'F', 'Interval', 'Timeout', 'Memory (Limit)'));
     foreach ($workers as $i => $worker) {
         $packet = $worker->getPacket();
         $table->addRow(array($i + 1, Resque\Worker::$statusText[$packet['status']], (string) $worker, Resque\Helpers\Util::human_time_diff($packet['started']), !empty($packet['job_id']) ? $packet['job_id'] . ' for ' . Resque\Helpers\Util::human_time_diff($packet['job_started']) : '-', $packet['processed'], $packet['cancelled'], $packet['failed'], $packet['interval'], $packet['timeout'], Resque\Helpers\Util::bytes($packet['memory']) . ' (' . $packet['memory_limit'] . ' MB)'));
     }
     $this->log((string) $table);
 }
Exemple #5
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $id = $input->getArgument('id');
     // Do a cleanup
     $worker = new Resque\Worker('*');
     $worker->cleanup();
     if ($id) {
         if (false === ($worker = Resque\Worker::hostWorker($id))) {
             $this->log('There is no worker with id "' . $id . '".', Resque\Logger::ERROR);
             return;
         }
         $workers = array($worker);
     } else {
         $workers = Resque\Worker::hostWorkers();
     }
     if (!count($workers)) {
         $this->log('<warn>There are no workers on this host</warn>');
     }
     foreach ($workers as $worker) {
         if (posix_kill($worker->getPid(), SIGTERM)) {
             $child = pcntl_fork();
             // Failed
             if ($child == -1) {
                 $this->log('Unable to fork, worker ' . $worker . ' has been stopped.', Resque\Logger::CRITICAL);
                 // Parent
             } elseif ($child > 0) {
                 $this->log('Worker <pop>' . $worker . '</pop> restarted.');
                 continue;
                 // Child
             } else {
                 $new_worker = new Resque\Worker($worker->getQueues(), $worker->getBlocking());
                 $new_worker->setInterval($worker->getInterval());
                 $new_worker->setTimeout($worker->getTimeout());
                 $new_worker->setMemoryLimit($worker->getMemoryLimit());
                 $new_worker->setLogger($this->logger);
                 $new_worker->work();
                 $this->log('Worker <pop>' . $worker . '</pop> restarted as <pop>' . $new_worker . '</pop>.');
             }
         } else {
             $this->log('Worker <pop>' . $worker . '</pop> <error>could not send TERM signal.</error>');
         }
     }
     exit(0);
 }
Exemple #6
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $queue = $this->getConfig('queue');
     $blocking = filter_var($this->getConfig('blocking'), FILTER_VALIDATE_BOOLEAN);
     // Create worker instance
     $worker = new Resque\Worker($queue, $blocking);
     $worker->setLogger($this->logger);
     if ($pidFile = $this->getConfig('pid')) {
         $worker->setPidFile($pidFile);
     }
     if ($interval = $this->getConfig('interval')) {
         $worker->setInterval($interval);
     }
     if ($timeout = $this->getConfig('timeout')) {
         $worker->setTimeout($timeout);
     }
     // The memory limit is the amount of memory we will allow the script to occupy
     // before killing it and letting a process manager restart it for us, which
     // is to protect us against any memory leaks that will be in the scripts.
     if ($memory = $this->getConfig('memory')) {
         $worker->setMemoryLimit($memory);
     }
     $worker->work();
 }
Exemple #7
0
 /**
  * Look for any jobs which are running but the worker is dead.
  * Meaning that they are also not running but left in limbo
  *
  * This is a form of garbage collection to handle cases where the
  * server may have been killed and the workers did not die gracefully
  * and therefore leave state information in Redis.
  *
  * @param array $queues list of queues to check
  */
 public static function cleanup(array $queues = array('*'))
 {
     $cleaned = array('zombie' => 0, 'processed' => 0);
     $redis = Redis::instance();
     if (in_array('*', $queues)) {
         $queues = (array) $redis->smembers(Queue::redisKey());
         sort($queues);
     }
     $workers = $redis->smembers(Worker::redisKey());
     foreach ($queues as $queue) {
         $jobs = $redis->zrangebyscore(Queue::redisKey($queue, 'running'), 0, time());
         foreach ($jobs as $payload) {
             $job = self::loadPayload($queue, $payload);
             $packet = $job->getPacket();
             if (!in_array($packet['worker'], $workers)) {
                 $job->fail(new Exception\Zombie());
                 $cleaned['zombie']++;
             }
         }
         $cleaned['processed'] = $redis->zremrangebyscore(Queue::redisKey($queue, 'processed'), 0, time() - \Resque::getConfig('default.expiry_time', \Resque::DEFAULT_EXPIRY_TIME));
     }
     return $cleaned;
 }
Exemple #8
0
 /**
  * Cleans up any dead hosts
  *
  * @return array List of cleaned hosts
  */
 public function cleanup()
 {
     $hosts = $this->redis->smembers(self::redisKey());
     $workers = $this->redis->smembers(Worker::redisKey());
     $cleaned = array('hosts' => array(), 'workers' => array());
     foreach ($hosts as $hostname) {
         $host = new static($hostname);
         if (!$this->redis->exists(self::redisKey($host))) {
             $this->redis->srem(self::redisKey(), (string) $host);
             $cleaned['hosts'][] = (string) $host;
         } else {
             $host_workers = $this->redis->smembers(self::redisKey($host));
             foreach ($host_workers as $host_worker) {
                 if (!in_array($host_worker, $workers)) {
                     $cleaned['workers'][] = $host_worker;
                     $this->redis->srem(self::redisKey($host), $host_worker);
                 }
             }
         }
     }
     return $cleaned;
 }
Exemple #9
0
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $host = $this->getConfig('listenhost');
     $port = $this->getConfig('listenport');
     $retry = $this->getConfig('listenretry');
     $timeout = $this->getConfig('listentimeout');
     $server = new Socket\Server(array('ip' => $host, 'port' => $port), $this->logger);
     do {
         try {
             $server->start();
         } catch (Socket\Exception $e) {
             if ($retry) {
                 $server->log('<error>Socket server failure: "' . $e->getMessage() . '". Retrying in ' . $timeout . ' seconds...</error>');
                 sleep($timeout);
                 continue;
             }
             throw $e;
         }
         break;
     } while ($retry);
     $command = $this;
     $server->onConnect(function ($server, &$client, $input) {
         //
     });
     $server->onDisconnect(function ($server, &$client, $message) {
         $server->send($client, $message);
     });
     $server->onReceive(function ($server, &$client, $input) use($command) {
         if (!($data = json_decode(trim($input), true))) {
             $data = trim($input);
         }
         if (is_array($data)) {
             $cmd = $data['cmd'];
             unset($data['cmd']);
         } else {
             try {
                 $input = new StringInput($data, new InputDefinition(array(new InputArgument('cmd', InputArgument::REQUIRED), new InputArgument('id', InputArgument::OPTIONAL), new InputOption('force', 'f', InputOption::VALUE_NONE), new InputOption('json', 'j', InputOption::VALUE_NONE))));
                 $cmd = $input->getArgument('cmd');
                 $data = array('id' => $input->getArgument('id'), 'force' => $input->getOption('force'), 'json' => $input->getOption('json'));
             } catch (\Exception $e) {
                 $server->send($client, 'Command error: ' . $e->getMessage());
                 return;
             }
         }
         switch (strtolower($cmd)) {
             case 'shell':
                 $server->send($client, 'Connected to php-resque on ' . $server . '. To quit, type "quit"');
                 break;
             case 'workers':
                 $workers = Worker::hostWorkers();
                 if (empty($workers)) {
                     $response = array('ok' => 0, 'message' => 'There are no workers running on this host.');
                     $server->send($client, $data['json'] ? json_encode($response) : $response['message']);
                     return;
                 }
                 if ($data['json']) {
                     $response = array('ok' => 1, 'data' => array());
                     foreach ($workers as $i => $worker) {
                         $response['data'][] = $worker->getPacket();
                     }
                     $server->send($client, json_encode($response));
                 } else {
                     $table = new Resque\Helpers\Table($command);
                     $table->setHeaders(array('#', 'Status', 'ID', 'Running for', 'Running job', 'P', 'C', 'F', 'Interval', 'Timeout', 'Memory (Limit)'));
                     foreach ($workers as $i => $worker) {
                         $packet = $worker->getPacket();
                         $table->addRow(array($i + 1, Worker::$statusText[$packet['status']], (string) $worker, Util::human_time_diff($packet['started']), !empty($packet['job_id']) ? $packet['job_id'] . ' for ' . Util::human_time_diff($packet['job_started']) : '-', $packet['processed'], $packet['cancelled'], $packet['failed'], $packet['interval'], $packet['timeout'], Util::bytes($packet['memory']) . ' (' . $packet['memory_limit'] . ' MB)'));
                     }
                     $server->send($client, (string) $table);
                 }
                 break;
             case 'worker:start':
             case 'worker:restart':
                 $response = array('ok' => 0, 'message' => 'This command is not yet supported remotely.');
                 $server->send($client, $data['json'] ? json_encode($response) : $response['message']);
                 break;
             case 'worker:pause':
             case 'worker:resume':
             case 'worker:stop':
             case 'worker:cancel':
                 $valid_id = false;
                 $id = preg_replace('/[^a-z0-9\\*:,\\.;-]/i', '', $data['id']);
                 if (!empty($id)) {
                     if (false === ($worker = Resque\Worker::hostWorker($id))) {
                         if ($data['json']) {
                             $response = array('ok' => 0, 'message' => 'Invalid worker id.');
                             $server->send($client, json_encode($response));
                         } else {
                             $server->send($client, "Usage:\n\t{$cmd} <worker_id>\n\n" . "Help: You must specify a valid worker id, to get a \n" . "list of workers use the \"workers\" command.");
                         }
                         return;
                     }
                     $workers = array($worker);
                 } else {
                     $workers = Resque\Worker::hostWorkers();
                     if (empty($workers)) {
                         $response = array('ok' => 0, 'message' => 'There are no workers on this host.');
                         $server->send($client, $data['json'] ? json_encode($response) : $response['message']);
                         return;
                     }
                 }
                 $cmd = $data['force'] ? 'worker:term' : $cmd;
                 $signals = array('worker:pause' => SIGUSR2, 'worker:resume' => SIGCONT, 'worker:stop' => SIGQUIT, 'worker:term' => SIGTERM, 'worker:cancel' => SIGUSR1);
                 $messages = array('worker:pause' => 'Paused worker %s', 'worker:resume' => 'Resumed worker %s', 'worker:stop' => 'Stopped worker %s', 'worker:term' => 'Force stopped worker %s', 'worker:cancel' => 'Cancelled running job on worker %s');
                 $response = array('ok' => 1, 'data' => array());
                 foreach ($workers as $worker) {
                     $pid = $worker->getPid();
                     if ($cmd == 'worker:cancel') {
                         $packet = $worker->getPacket();
                         $job_pid = (int) $packet['job_pid'];
                         if ($job_pid and posix_kill($job_pid, 0)) {
                             $pid = $job_pid;
                         } else {
                             $response['data'][] = array('ok' => 0, 'message' => 'The worker ' . $worker . ' has no running job to cancel.');
                             continue;
                         }
                     }
                     if (posix_kill($pid, $signals[$cmd])) {
                         $response['data'][] = array('ok' => 1, 'message' => sprintf($messages[$cmd], $worker));
                     } else {
                         $response['data'][] = array('ok' => 0, 'message' => 'There was an error sending the signal, please try again.');
                     }
                 }
                 $server->send($client, $data['json'] ? json_encode($response) : implode(PHP_EOL, array_map(function ($d) {
                     return $d['message'];
                 }, $response['data'])));
                 break;
             case 'job:queue':
                 $response = array('ok' => 0, 'message' => 'Cannot queue remotely as it makes no sense. Use command `resque job:queue <job> <args> [--queue=<queue> [--delay=<delay>]]` locally.');
                 $server->send($client, $data['json'] ? json_encode($response) : $response['message']);
                 break;
             case 'cleanup':
                 $host = new Host();
                 $cleaned_hosts = $host->cleanup();
                 $worker = new Worker('*');
                 $cleaned_workers = $worker->cleanup();
                 $cleaned_hosts = array_merge_recursive($cleaned_hosts, $host->cleanup());
                 $cleaned_jobs = Job::cleanup();
                 if ($data['json']) {
                     $response = array('ok' => 1, 'data' => array_merge($cleaned_hosts, $cleaned_workers, $cleaned_jobs));
                     $server->send($client, json_encode($response));
                 } else {
                     $output = 'Cleaned hosts: ' . json_encode($cleaned_hosts['hosts']) . PHP_EOL . 'Cleaned workers: ' . json_encode(array_merge($cleaned_hosts['workers'], $cleaned_workers)) . PHP_EOL . 'Cleaned ' . $cleaned_jobs['zombie'] . ' zombie job' . ($cleaned_jobs['zombie'] == 1 ? '' : 's') . PHP_EOL . 'Cleared ' . $cleaned_jobs['processed'] . ' processed job' . ($cleaned_jobs['processed'] == 1 ? '' : 's');
                 }
                 $server->send($client, $output);
                 break;
             case 'shutdown':
                 $server->shutdown();
                 break;
             case 'quit':
             case 'exit':
                 $server->disconnect($client);
                 break;
             default:
                 $response = array('ok' => 0, 'message' => 'Sorry, I don\'t know what to do with command "' . $cmd . '".');
                 $server->send($client, $data['json'] ? json_encode($response) : $response['message']);
                 break;
         }
     });
     $server->run();
 }