/** * Set up the GearmanWorker to run in non-blocking mode * * This allows you to do work "in between" jobs when its idle * * Events emitted: * - Gearman.beforeWork: Called before GearmanWorker::work() * - Gearman.afterWork: Called after GearmanWorker::work() actually processed a job * - Gearman.beforeWait: Called before Gearman::wait() is called * - Gearman.afterWait: Called after Gearman::wait() is called * * N.B: Gearman.beforeWork will be called even if there is no jobs to be processed, * it's meant as a simple wrapper around GearmanWorker::work() and GearmanWorker::wait() * * All events can abort the infinite loop by calling $event->stopPropagation(); * * @return void */ protected function _work() { $this->_worker->addOptions(GEARMAN_WORKER_NON_BLOCKING); // Infinite loop of doom until we die! while (true) { if (!$this->_triggerEvent('Gearman.beforeWork')) { break; } $this->_worker->work(); if (!$this->_triggerEvent('Gearman.afterWork')) { break; } // If we processed a job, don't bother to wait if ($this->_worker->returnCode() == GEARMAN_SUCCESS) { continue; } if (!$this->_triggerEvent('Gearman.beforeWait')) { break; } $this->_worker->wait(); if (!$this->_triggerEvent('Gearman.afterWait')) { break; } } }
/** * A wrapper for the normal GearmanWorker::work() method, with some additional settings * * @param string $name the name of the task this worker implements * @return void */ public function work($name = 'gearman') { $this->log(sprintf("Starting %s worker", $name), 'info', 'gearman'); $worker = $this->getWorker(); $worker->addOptions(GEARMAN_WORKER_NON_BLOCKING); $this->_setupEvents(); while (true) { if (!$this->_triggerEvent('Gearman.beforeWork')) { break; } $worker->work(); if (!$this->_triggerEvent('Gearman.afterWork')) { break; } // If we processed a job, don't bother to wait if ($worker->returnCode() == GEARMAN_SUCCESS) { continue; } $this->_worker->wait(); } }
/** * Starts a worker for the PECL library * * @param array $worker_list List of worker functions to add * @param array $timeouts list of worker timeouts to pass to server * @return void * */ protected function start_lib_worker($worker_list, $timeouts = array()) { $thisWorker = new GearmanWorker(); $thisWorker->addOptions(GEARMAN_WORKER_NON_BLOCKING); $thisWorker->setTimeout(5000); foreach ($this->servers as $s) { $this->log("Adding server {$s}", GearmanManager::LOG_LEVEL_WORKER_INFO); // see: https://bugs.php.net/bug.php?id=63041 try { $thisWorker->addServers($s); } catch (\GearmanException $e) { if ($e->getMessage() !== 'Failed to set exception option') { throw $e; } } } foreach ($worker_list as $w) { $timeout = isset($timeouts[$w]) ? $timeouts[$w] : null; $this->log("Adding job {$w} ; timeout: " . $timeout, GearmanManager::LOG_LEVEL_WORKER_INFO); $thisWorker->addFunction($w, array($this, "do_job"), $this, $timeout); } $start = time(); while (!$this->stop_work) { if (@$thisWorker->work() || $thisWorker->returnCode() == GEARMAN_IO_WAIT || $thisWorker->returnCode() == GEARMAN_NO_JOBS) { if ($thisWorker->returnCode() == GEARMAN_SUCCESS) { continue; } if (!@$thisWorker->wait()) { if ($thisWorker->returnCode() == GEARMAN_NO_ACTIVE_FDS) { sleep(5); } } } /** * Check the running time of the current child. If it has * been too long, stop working. */ if ($this->max_run_time > 0 && time() - $start > $this->max_run_time) { $this->log("Been running too long, exiting", GearmanManager::LOG_LEVEL_WORKER_INFO); $this->stop_work = true; } if (!empty($this->config["max_runs_per_worker"]) && $this->job_execution_count >= $this->config["max_runs_per_worker"]) { $this->log("Ran {$this->job_execution_count} jobs which is over the maximum({$this->config['max_runs_per_worker']}), exiting", GearmanManager::LOG_LEVEL_WORKER_INFO); $this->stop_work = true; } } $thisWorker->unregisterAll(); }
/** * Starts a worker for the PECL library * * @param array $worker_list List of worker functions to add * @return void * */ protected function start_lib_worker($worker_list) { $thisWorker = new GearmanWorker(); $thisWorker->addOptions(GEARMAN_WORKER_NON_BLOCKING); $thisWorker->setTimeout(5000); foreach ($this->servers as $s) { $this->log("Adding server {$s}", GearmanManager::LOG_LEVEL_WORKER_INFO); $thisWorker->addServers($s); } foreach ($worker_list as $w) { $this->log("Adding job {$w}", GearmanManager::LOG_LEVEL_WORKER_INFO); $thisWorker->addFunction($w, array($this, "do_job"), $this); } $start = time(); while (!$this->stop_work) { if (@$thisWorker->work() || $thisWorker->returnCode() == GEARMAN_IO_WAIT || $thisWorker->returnCode() == GEARMAN_NO_JOBS) { if ($thisWorker->returnCode() == GEARMAN_SUCCESS) { continue; } if (!@$thisWorker->wait()) { if ($thisWorker->returnCode() == GEARMAN_NO_ACTIVE_FDS) { sleep(5); } } } /** * Check the running time of the current child. If it has * been too long, stop working. */ if ($this->max_run_time > 0 && time() - $start > $this->max_run_time) { $this->log("Been running too long, exiting", GearmanManager::LOG_LEVEL_WORKER_INFO); $this->stop_work = true; } if (!empty($this->config["max_runs_per_worker"]) && $this->job_execution_count >= $this->config["max_runs_per_worker"]) { $this->log("Ran {$this->job_execution_count} jobs which is over the maximum({$this->config['max_runs_per_worker']}), exiting", GearmanManager::LOG_LEVEL_WORKER_INFO); $this->stop_work = true; } } $thisWorker->unregisterAll(); }
/** * The Gearman Worker processes requests passed to it from a Gearman * server. This class should be invoked as a daemon using the CLI * interface. Multiple instances can be created to handle multiple requests * asynchronously. * * // Initialize the Gearman Worker (in bootstrap) * Request_Async_Gearman::worker(); * exit(0); * * To create a daemon script, run the following command from your command * line. * * php /path/to/index.php * * @return void */ public static function worker() { $worker = new GearmanWorker(); $worker->addServer(); $worker->addFunction('request_async', array('Request_Async_Gearman', 'execute_request'), Request_Async_Gearman::$context); echo Request_Async_Gearman::$context . ': Starting worker.' . "\n"; while ($worker->work() or $worker->returnCode() == GEARMAN_IO_WAIT or $worker->returnCode() == GEARMAN_NO_JOBS) { if ($worker->returnCode() == GEARMAN_SUCCESS) { continue; } echo Request_Async_Gearman::$context . ': Waiting for next job...' . "\n"; if (!$worker->wait()) { if ($worker->returnCode() == GEARMAN_NO_ACTIVE_FDS) { usleep(100); continue; } } break; } echo Request_Async_Gearman::$context . ': Stopping worker.' . "\n"; echo Request_Async_Gearman::$context . ': Worker error' . $worker->error() . "\n"; }
protected function wait(\GearmanWorker $worker) { // @!? if (@$worker->wait()) { return true; } switch ($worker->returnCode()) { case GEARMAN_SUCCESS: return true; case GEARMAN_NO_ACTIVE_FDS: sleep(5); return true; default: break; } return false; }
// Fetch a photo from twitpic $worker->addFunction("fetchPhoto", "fetchPhoto"); // This worker will destroy itself in 5 seconds. $worker->setTimeout(5000); // Keep worker alive as long as there are jobs while (@$worker->work() || $worker->returnCode() == GEARMAN_IO_WAIT || $worker->returnCode() == GEARMAN_NO_JOBS){ if ($worker->returnCode() == GEARMAN_SUCCESS){ echo date('d-m-Y H:i:s') . "| Job Successful \n"; continue; } if (!@$worker->wait()) { if ($worker->returnCode() == GEARMAN_NO_ACTIVE_FDS) { // We are not connected to the Gearman Server // We shall not hammer the Gearman Server // We have patience, not much, but some. sleep(5); continue; } break; } } /** * Fetch a page with photo id's. Since there is paging on twitpic, we have to fetch every page *