FileMonitor.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. <?php
  2. require_once WORKERMAN_ROOT_DIR . 'man/Core/SocketWorker.php';
  3. /**
  4. *
  5. * 用这个worker监控文件更新
  6. * 当文件更新后会给每个worker进程发送平滑重启信号
  7. * 做到文件更新自动加载到内存
  8. *
  9. * @author walkor <worker-man@qq.com>
  10. */
  11. class FileMonitor extends Man\Core\AbstractWorker
  12. {
  13. /**
  14. * 需要监控的文件
  15. * @var array
  16. */
  17. protected $filesToInotify = array();
  18. /**
  19. * 终端已经关闭
  20. * @var bool
  21. */
  22. protected $terminalClosed = false;
  23. /**
  24. * 该worker进程开始服务的时候会触发一次
  25. * @return bool
  26. */
  27. public function start()
  28. {
  29. if(\Man\Core\Lib\Config::get('workerman.debug') != 1)
  30. {
  31. return;
  32. }
  33. if(!\Man\Core\Master::getQueueId())
  34. {
  35. while(1)
  36. {
  37. sleep(PHP_INT_MAX);
  38. }
  39. }
  40. $msg_type = $message = 0;
  41. \Man\Core\Lib\Task::init();
  42. \Man\Core\Lib\Task::add(1, array($this, 'sendSignalAndGetResult'));
  43. \Man\Core\Lib\Task::add(1, array($this, 'checkFilesModify'));
  44. \Man\Core\Lib\Task::add(1, array($this, 'checkTty'));
  45. while(1)
  46. {
  47. $this->collectFiles(true);
  48. if($this->hasShutDown())
  49. {
  50. exit(0);
  51. }
  52. }
  53. return true;
  54. }
  55. /**
  56. * 发送文件上报信号,并收集文件列表
  57. * @return void
  58. */
  59. public function sendSignalAndGetResult()
  60. {
  61. $this_pid = posix_getpid();
  62. $pid_worker_map = $this->getPidWorkerMap();
  63. foreach($pid_worker_map as $pid=>$worker_name)
  64. {
  65. if($pid != $this_pid)
  66. {
  67. posix_kill($pid, SIGUSR2);
  68. }
  69. $this->collectFiles();
  70. }
  71. }
  72. /**
  73. * 从消息队列中获取要监控的文件列表
  74. * @param bool $block
  75. * @return void
  76. */
  77. protected function collectFiles($block = false)
  78. {
  79. $msg_type = $message = null;
  80. $flag = $block ? 0 : MSG_IPC_NOWAIT;
  81. if(msg_receive(\Man\Core\Master::getQueueId(), self::MSG_TYPE_FILE_MONITOR, $msg_type, 10000, $message, true, $flag))
  82. {
  83. foreach($message as $file)
  84. {
  85. if(!isset($this->filesToInotify[$file]))
  86. {
  87. $stat = @stat($file);
  88. $mtime = isset($stat['mtime']) ? $stat['mtime'] : 0;
  89. $this->filesToInotify[$file] = $mtime;
  90. }
  91. }
  92. }
  93. }
  94. /**
  95. * 发送信号给所有worker
  96. * @param integer $signal
  97. * @return void
  98. */
  99. public function sendSignalToAllWorker($signal)
  100. {
  101. $this_pid = posix_getpid();
  102. $pid_worker_map = $this->getPidWorkerMap();
  103. foreach($pid_worker_map as $pid=>$worker_name)
  104. {
  105. if($pid != $this_pid)
  106. {
  107. posix_kill($pid, $signal);
  108. }
  109. }
  110. }
  111. /**
  112. * 检查文件更新时间,如果有更改则平滑重启服务(开发的时候用到)
  113. * @return void
  114. */
  115. public function checkFilesModify()
  116. {
  117. $has_send_signal = false;
  118. foreach($this->filesToInotify as $file=>$mtime)
  119. {
  120. clearstatcache();
  121. $stat = @stat($file);
  122. if(false === $stat)
  123. {
  124. unset($this->filesToInotify[$file]);
  125. continue;
  126. }
  127. $mtime_now = $stat['mtime'];
  128. if($mtime != $mtime_now)
  129. {
  130. $this->filesToInotify[$file] = $mtime_now;
  131. if(!$has_send_signal)
  132. {
  133. \Man\Core\Lib\Log::add("$file updated and reload workers");
  134. $this->sendSignalToAllWorker(SIGHUP);
  135. $has_send_signal = true;
  136. }
  137. }
  138. }
  139. }
  140. /**
  141. * 检查控制终端是否已经关闭, 如果控制终端关闭,则停止打印数据到终端(发送平滑重启信号)
  142. * @return void
  143. */
  144. public function checkTty()
  145. {
  146. if(!$this->terminalClosed && !posix_ttyname(STDOUT))
  147. {
  148. // 日志
  149. $this->notice("terminal closed and restart worker");
  150. // worker重启时会检测终端是否关闭
  151. $this->sendSignalToAllWorker(SIGHUP);
  152. // 设置标记
  153. $this->terminalClosed = true;
  154. }
  155. }
  156. }