Fork.php 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. <?php
  2. namespace app\process;
  3. use app\framework\Log\SimpleLog;
  4. use Illuminate\Support\Facades\Redis;
  5. /**
  6. * 只能在cli环境下使用
  7. * Trait Fork
  8. * @package app\daemon
  9. */
  10. trait Fork
  11. {
  12. /**
  13. * @var SimpleLog
  14. */
  15. private $pidLog;
  16. private function log()
  17. {
  18. if (!$this->pidLog) {
  19. $this->pidLog = new SimpleLog('pid');
  20. }
  21. return $this->pidLog;
  22. }
  23. static protected function pidKey($pidKey)
  24. {
  25. return $pidKey;
  26. }
  27. protected $pidKey;
  28. protected function cProcess($closure, $pidKey)
  29. {
  30. pcntl_signal(SIGCHLD, SIG_IGN);
  31. $pid = pcntl_fork();
  32. if ($pid == -1) {
  33. die('子进程创建失败');
  34. } else if ($pid) {
  35. // 父进程执行继续执行
  36. return $pid;
  37. } else {
  38. $this->log()->add($pidKey, [getmypid()]);
  39. //设置当前进程为会话组长
  40. if (posix_setsid() < 0) {
  41. exit('Session leader set failed.' . PHP_EOL);
  42. }
  43. \srand();
  44. \mt_srand();
  45. //改变当前目录为根目录
  46. chdir('/');
  47. //重设文件掩码
  48. umask(0);
  49. //关闭打开的文件描述符
  50. fclose(STDIN);
  51. fclose(STDOUT);
  52. fclose(STDERR);
  53. self::setProcessTitle('php yun_shop fork ' . $pidKey);
  54. // 生成新的redis和mysql实例,新的进程如果使用相同旧实例,任何一个进程关闭数据库连接后,其他进程将无法连接数据报错
  55. app('redis')->refresh();
  56. app('db')->refresh();
  57. $this->pidKey = $pidKey;
  58. Redis::hset('forkPids:'.gethostname(),$this->pidKey,getmypid());
  59. Redis::hset('ProcessData', getmypid(),time());
  60. // 子进程执行完立刻退出,避免递归执行
  61. call_user_func($closure);
  62. Redis::hdel('ProcessData', getmypid(),time());
  63. Redis::hdel('forkPids:'.gethostname(),$this->pidKey);
  64. exit($pid);
  65. }
  66. }
  67. /**
  68. * Set process name.
  69. *
  70. * @param string $title
  71. * @return void
  72. */
  73. protected static function setProcessTitle($title)
  74. {
  75. \set_error_handler(function () {
  76. });
  77. // >=php 5.5
  78. if (\function_exists('cli_set_process_title')) {
  79. \cli_set_process_title($title);
  80. } // Need proctitle when php<=5.5 .
  81. elseif (\extension_loaded('proctitle') && \function_exists('setproctitle')) {
  82. \setproctitle($title);
  83. }
  84. \restore_error_handler();
  85. }
  86. }