安装

https://www.yuque.com/docs/share/1d5ba458-e729-4059-afcf-d9ba3a33ede3?#

使用 docker

  1. docker search php
  2. webdevops/php-nginx
  3. docker run -p 80:80 -p 443:443 -p 9000:9000 -p 9001:9001 -v /Users/mac/PhpstormProjects:/app -itd 4edee5cecbe7

1. 配置文件

配置简介 : https://www.kancloud.cn/dargon/supervisor/1134310

supervisor_demo.conf

  1. [unix_http_server]
  2. file=/run/supervisord.sock ; (the path to the socket file)
  3. [inet_http_server] ; inet (TCP) server disabled by default
  4. port=0.0.0.0:9001 ; (ip_address:port specifier, *:port for all iface)
  5. username=admin ; (default is no username (open server))
  6. password=123456 ; (default is no password (open server))
  7. [supervisord]
  8. logfile=/var/log/supervisord.log ; (main log file;default $CWD/supervisord.log)
  9. logfile_maxbytes=100MB
  10. logfile_backups=10
  11. loglevel=info ; (log level;default info; others: debug,warn,trace)
  12. [rpcinterface:supervisor]
  13. supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
  14. [supervisorctl]
  15. serverurl=unix:///run/supervisord.sock ; use a unix:// URL for a unix socket
  16. [program:demo_worker_name1]
  17. directory=/app/demo_supervisor
  18. command=php main1.php
  19. autostart=true
  20. autorestart=true
  21. startsecs=10
  22. startretries=2
  23. numprocs=1
  24. process_name=%(process_num)02d
  25. user=root
  26. stdout_logfile=/var/log/demo1.log
  27. stderr_logfile=/var/log/demo1_err.log
  28. [program:demo_worker_name2]
  29. directory=/app/demo_supervisor
  30. command=php main2.php
  31. autostart=true
  32. autorestart=true
  33. startsecs=10
  34. startretries=2
  35. numprocs=2
  36. process_name=%(process_num)02d
  37. user=root
  38. stdout_logfile=/var/log/demo2.log
  39. stderr_logfile=/var/log/demo2_err.log
  40. [include]
  41. files = /etc/supervisor.d/*.ini

1. 启动&应用配置

  1. supervisord -c /app/demo_supervisor/supervisor_demo.conf

3. 重新应用配置文件

  1. supervisorctl -c /app/demo_supervisor/supervisor_demo.conf
  2. > reload

4. 测试文件

main1.php

  1. <?php
  2. $i = 0;
  3. while (true) {
  4. $i++;
  5. print_r("num: " . $i . PHP_EOL);
  6. sleep(1);
  7. if ($i > 300) {
  8. break;
  9. }
  10. }
  11. print_r("end");

main2.php

  1. <?php
  2. for ($num = 1; $num <= 5; ++$num) {
  3. $pid = pcntl_fork();
  4. if (!$pid) {
  5. printNum($num);
  6. }
  7. }
  8. function printNum($num) {
  9. $i = 0;
  10. while (true) {
  11. $i++;
  12. print_r("num: " . $num . " i :" . $i . PHP_EOL);
  13. sleep(1);
  14. if ($i > 300) {
  15. break;
  16. }
  17. }
  18. exit($num . "fork end");
  19. }
  20. while (pcntl_waitpid(0, $status) != -1) {
  21. $status = pcntl_wexitstatus($status);
  22. echo "Child $status completed\n";
  23. }
  24. /**
  25. $j = 0;
  26. while (true) {
  27. $j++;
  28. print_r("now: " . $j . PHP_EOL);
  29. sleep(1);
  30. }
  31. */

监听事件到mysql中.

  1. #!/usr/local/supervisord/bin/python
  2. # coding:utf-8
  3. # author: mk
  4. from supervisor import childutils
  5. import socket
  6. import pymysql
  7. import pymysql.cursors
  8. import sys
  9. import os
  10. import time
  11. def execute(hostname, ip, process_name, process_pid, from_state, curr_state, timestamp):
  12. """
  13. 数据写入/更新,由主机名,IP地址,进程名组成唯一索引
  14. :param hostname: 主机名
  15. :param ip: IP地址
  16. :param process_name: 进程名
  17. :param process_pid: 进程ID
  18. :param from_state: 上次状态
  19. :param curr_state: 当前状态
  20. :param timestamp: 更新时间
  21. :return: void
  22. """
  23. user, passwd = ('root', '')
  24. conn = pymysql.connect(
  25. host="192.168.199.202",
  26. port=3306,
  27. user=user,
  28. db='test',
  29. password=passwd
  30. )
  31. with conn:
  32. with conn.cursor() as cursor:
  33. # 查询一条单记录
  34. sql = "SELECT `id` FROM `supervisor` WHERE `hostname`=%s AND `ip`=%s AND `process_name`=%s"
  35. count = cursor.execute(sql, (hostname,ip, process_name))
  36. if count:
  37. sql = "UPDATE `supervisor` SET `process_pid`=%s,`from_state`=%s,`curr_state`=%s, `timestamp`=%s WHERE `hostname`=%s AND `ip`=%s AND `process_name`=%s"
  38. cursor.execute(sql, (process_pid, from_state, curr_state, timestamp, hostname,ip, process_name))
  39. else:
  40. sql = "INSERT INTO `supervisor` (`id`,`hostname`, `ip`, `process_name`, `process_pid`, `from_state`, `curr_state`,`timestamp`) VALUES (null,%s,%s,%s,%s,%s,%s,%s)"
  41. cursor.execute(sql, (hostname, ip, process_name, process_pid, from_state, curr_state, timestamp))
  42. conn.commit()
  43. class Agent(object):
  44. def __init__(self):
  45. self.stdout = sys.stdout
  46. self.stdin = sys.stdin
  47. self.stderr = sys.stderr
  48. def runForever(self, debug=False):
  49. while True:
  50. headers, payload = childutils.listener.wait(self.stdin, self.stdout)
  51. if not headers['eventname'] in [
  52. 'PROCESS_STATE_EXITED', # 退出
  53. 'PROCESS_STATE_STARTING', # 启动
  54. 'PROCESS_STATE_RUNNING', # 运行
  55. 'PROCESS_STATE_BACKOFF', # 倒退
  56. 'PROCESS_STATE_STOPPING', # 停止
  57. 'PROCESS_STATE_STOPPED', # 停止
  58. ]:
  59. pass
  60. pheaders, pdata = childutils.eventdata(payload + '\n')
  61. hostname = socket.gethostname()
  62. ip = socket.gethostbyname(hostname)
  63. process_name = pheaders['processname']
  64. process_pid = pheaders['pid']
  65. from_state = pheaders['from_state']
  66. curr_state = headers['eventname'].split('_')[2]
  67. if debug:
  68. with open('/tmp/debug', 'w+') as file:
  69. file.write(str(headers)+"\n")
  70. file.write(str(payload)+"\n")
  71. execute(hostname, ip, process_name, process_pid, from_state, curr_state, int(time.time()))
  72. childutils.listener.ok(self.stdout)
  73. def main():
  74. if not 'SUPERVISOR_SERVER_URL' in os.environ:
  75. sys.stderr.write('crashmail must be run as a supervisor event '
  76. 'listener\n')
  77. sys.stderr.flush()
  78. return
  79. agent = Agent()
  80. agent.runForever(True)
  81. if __name__ == '__main__':
  82. main()