PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/GearmanManager/Bridge/GearmanPearManager.php

http://github.com/brianlmoon/GearmanManager
PHP | 316 lines | 180 code | 73 blank | 63 comment | 38 complexity | 96f68aade05a466145b524bdaf42e182 MD5 | raw file
  1. <?php
  2. namespace GearmanManager\Bridge;
  3. use \GearmanManager\GearmanManager;
  4. /**
  5. * Implements the worker portions of the PEAR Net_Gearman library
  6. *
  7. * @author Brian Moon <brian@moonspot.net>
  8. * @copyright 1997-Present Brian Moon
  9. * @package GearmanManager
  10. *
  11. */
  12. if (!class_exists("GearmanManager")) {
  13. require dirname(__FILE__)."/../GearmanManager.php";
  14. }
  15. /**
  16. * Implements the worker portions of the PEAR Net_Gearman library
  17. */
  18. class GearmanPearManager extends GearmanManager {
  19. public static $LOG = array();
  20. private $start_time;
  21. private $last_idle_info_time;
  22. private $last_idle_debug_time;
  23. private $worker;
  24. /**
  25. * Starts a worker for the PEAR library
  26. *
  27. * @param array $worker_list List of worker functions to add
  28. * @param array $timeouts list of worker timeouts to pass to server
  29. * @return void
  30. *
  31. */
  32. protected function start_lib_worker($worker_list, $timeouts = array()) {
  33. /**
  34. * Require PEAR Net_Gearman libs
  35. */
  36. define('NET_GEARMAN_JOB_PATH', $this->worker_dir);
  37. if (!class_exists("Net_Gearman_Job_Common")) {
  38. require "Net/Gearman/Job/Common.php";
  39. }
  40. if (!class_exists("Net_Gearman_Job")) {
  41. require "Net/Gearman/Job.php";
  42. }
  43. if (!class_exists("Net_Gearman_Worker")) {
  44. require "Net/Gearman/Worker.php";
  45. }
  46. try {
  47. $this->worker = new \Net_Gearman_Worker($this->servers);
  48. } catch (Net_Gearman_Exception $e) {
  49. $this->log($e->message, GearmanManager::LOG_LEVEL_WORKER_INFO);
  50. return;
  51. }
  52. $server_status = $this->worker->connection_status();
  53. if ($server_status["connected"] == 0) {
  54. $this->log("Failed to connect to any servers", GearmanManager::LOG_LEVEL_WORKER_INFO);
  55. } elseif ($server_status["disconnected"] > 0) {
  56. $message = "Failed to connect to the following servers: ";
  57. foreach ($server_status["servers"] as $server => $status) {
  58. if (!$status) {
  59. $message.= "$server,";
  60. }
  61. }
  62. $message = substr($message, 0, -1);
  63. $this->log($message, GearmanManager::LOG_LEVEL_WORKER_INFO);
  64. }
  65. foreach ($worker_list as $w) {
  66. $timeout = (isset($timeouts[$w]) ? $timeouts[$w] : null);
  67. $message = "Adding job $w";
  68. if ($timeout) {
  69. $message.= "; timeout: $timeout";
  70. }
  71. $this->log($message, GearmanManager::LOG_LEVEL_WORKER_INFO);
  72. $this->worker->addAbility($w, $timeout, $this->functions[$w]);
  73. }
  74. $this->worker->attachCallback(array($this, 'job_start'), \Net_Gearman_Worker::JOB_START);
  75. $this->worker->attachCallback(array($this, 'job_complete'), \Net_Gearman_Worker::JOB_COMPLETE);
  76. $this->worker->attachCallback(array($this, 'job_fail'), \Net_Gearman_Worker::JOB_FAIL);
  77. $this->start_time = time();
  78. $this->worker->beginWork(array($this, "monitor"));
  79. }
  80. /**
  81. * Monitor call back for worker. Return true to stop worker
  82. *
  83. * @param bool $idle If true the worker was idle
  84. * @param int $lastJob The time the last job was run
  85. * @return bool
  86. *
  87. */
  88. public function monitor($idle, $lastJob) {
  89. if ($this->max_run_time > 0 && time() - $this->start_time > $this->max_run_time) {
  90. $this->log("Been running too long, exiting", GearmanManager::LOG_LEVEL_WORKER_INFO);
  91. $this->stop_work = true;
  92. }
  93. if (!empty($this->config["max_runs_per_worker"]) && $this->job_execution_count >= $this->config["max_runs_per_worker"]) {
  94. $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);
  95. $this->stop_work = true;
  96. }
  97. if (!$this->stop_work) {
  98. $time = time() - $lastJob;
  99. if (empty($this->last_idle_info_time)) {
  100. $this->last_idle_info_time = time();
  101. }
  102. if (empty($this->last_idle_debug_time)) {
  103. $this->last_idle_debug_time = time();
  104. }
  105. $servers = $this->worker->connection_status();
  106. $connected_servers = array();
  107. $disconnected_servers = array();
  108. foreach ($servers["servers"] as $server => $connected) {
  109. if ($connected) {
  110. $connected_servers[] = $server;
  111. } else {
  112. $disconnected_servers[] = $server;
  113. }
  114. }
  115. /**
  116. * If we are disconnected to any servers, log as info the idle status
  117. * every 30 seconds.
  118. *
  119. * Otherwise, log it at an interval based on max run time if set.
  120. */
  121. if ((count($disconnected_servers) > 0 && time() - $this->last_idle_info_time >= 30) ||
  122. ($this->max_run_time > 0 && time() - $this->last_idle_info_time >= $this->max_run_time/50)) {
  123. $level = GearmanManager::LOG_LEVEL_WORKER_INFO;
  124. $this->last_idle_info_time = time();
  125. } elseif (time() - $this->last_idle_debug_time >= 10) {
  126. $level = GearmanManager::LOG_LEVEL_DEBUG;
  127. $this->last_idle_debug_time = time();
  128. } else {
  129. $level = GearmanManager::LOG_LEVEL_CRAZY;
  130. }
  131. $idle_message = "Worker as been idle for $time seconds.";
  132. if (count($connected_servers)) {
  133. $idle_message.=" Connected to ".implode(",", $connected_servers).".";
  134. }
  135. if (count($disconnected_servers)) {
  136. $idle_message.=" Disconnected from ".implode(",", $disconnected_servers).".";
  137. }
  138. $this->log($idle_message, $level);
  139. }
  140. return $this->stop_work;
  141. }
  142. /**
  143. * Call back for when jobs are started
  144. */
  145. public function job_start($handle, $job, $args) {
  146. $this->job_execution_count++;
  147. if ( ! empty($this->config["max_runs_per_worker"]) ) {
  148. $message = sprintf('(%s) Starting Job (%d/%d): %s', $handle, $this->job_execution_count, $this->config["max_runs_per_worker"], $job);
  149. $this->log($message, GearmanManager::LOG_LEVEL_WORKER_INFO);
  150. } else {
  151. $this->log("($handle) Starting Job: $job", GearmanManager::LOG_LEVEL_WORKER_INFO);
  152. }
  153. $this->log("($handle) Workload: ".json_encode($args), GearmanManager::LOG_LEVEL_DEBUG);
  154. self::$LOG = array();
  155. }
  156. /**
  157. * Call back for when jobs are completed
  158. */
  159. public function job_complete($handle, $job, $result) {
  160. $this->log("($handle) Completed Job: $job", GearmanManager::LOG_LEVEL_WORKER_INFO);
  161. $this->log_result($handle, $result);
  162. }
  163. /**
  164. * Call back for when jobs fail
  165. */
  166. public function job_fail($handle, $job, $result) {
  167. $message = "($handle) Failed Job: $job: ".$result->getMessage();
  168. $this->log($message, GearmanManager::LOG_LEVEL_WORKER_INFO);
  169. $this->log_result($handle, $result);
  170. }
  171. /**
  172. * Logs the result of complete/failed jobs
  173. *
  174. * @param mixed $result Result returned from worker
  175. * @return void
  176. *
  177. */
  178. private function log_result($handle, $result) {
  179. if (!empty(self::$LOG)) {
  180. foreach (self::$LOG as $l) {
  181. if (!is_scalar($l)) {
  182. $l = explode("\n", trim(print_r($l, true)));
  183. } elseif (strlen($l) > 256) {
  184. $l = substr($l, 0, 256)."...(truncated)";
  185. }
  186. if (is_array($l)) {
  187. $log_message = "";
  188. foreach ($l as $ln) {
  189. $log_message.= "($handle) $ln\n";
  190. }
  191. $this->log($log_message, GearmanManager::LOG_LEVEL_WORKER_INFO);
  192. } else {
  193. $this->log("($handle) $l", GearmanManager::LOG_LEVEL_WORKER_INFO);
  194. }
  195. }
  196. }
  197. $result_log = $result;
  198. if (!is_scalar($result_log)) {
  199. $result_log = explode("\n", trim(print_r($result_log, true)));
  200. } elseif (strlen($result_log) > 256) {
  201. $result_log = substr($result_log, 0, 256)."...(truncated)";
  202. }
  203. if (is_array($result_log)) {
  204. $log_message = "";
  205. foreach ($result_log as $ln) {
  206. $log_message.="($handle) $ln\n";
  207. }
  208. $this->log($log_message, GearmanManager::LOG_LEVEL_DEBUG);
  209. } else {
  210. $this->log("($handle) $result_log", GearmanManager::LOG_LEVEL_DEBUG);
  211. }
  212. }
  213. /**
  214. * Validates the PECL compatible worker files/functions
  215. */
  216. protected function validate_lib_workers() {
  217. /**
  218. * Yes, we include these twice because this function is called
  219. * by a different process than the other location where these
  220. * are included.
  221. */
  222. if (!class_exists("Net_Gearman_Job_Common")) {
  223. require "Net/Gearman/Job/Common.php";
  224. }
  225. if (!class_exists("Net_Gearman_Job")) {
  226. require "Net/Gearman/Job.php";
  227. }
  228. /**
  229. * Validate functions
  230. */
  231. foreach ($this->functions as $name => $func) {
  232. $class = $this->prefix.$name;
  233. if (!class_exists($class, false)) {
  234. include $func['path'];
  235. }
  236. if (!class_exists($class, false) && !method_exists($class, "run")) {
  237. $this->log("Class $class not found in {$func['path']} or run method not present");
  238. posix_kill($this->pid, SIGUSR2);
  239. exit();
  240. }
  241. }
  242. }
  243. }