FileMonitor.php 4.3 KB

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