php多进程管理器
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src
tests
.gitignore
README.md
composer.json

README.md

process_manage

php多进程管理器



业务场景

在实际业务场景中,我们可能需要定时执行或者近乎实时到业务逻辑,简单的可以使用unix自带的crontab实现。但是对于一些实时性要求比较高的业务就不适用了,所以我们就需要一个常驻内存的任务管理工具,为了保证实时性,一方面我们让它一直执行任务(适当的睡眠,保证cpu不被100%占用),另一方面我们实现多进程保证并发的执行任务。



简述

基于php-cli模式实现master(父进程)-worker(子进程)的多进程管理器。

  • 创建:一个master fork出多个worker
  • 运行:
    • master通过信号(signal)控制多个worker的生命周期(master会阻塞的等待信号或者子进程退出)
    • worker会在生命周期中执行预定的任务


依赖

  • php: >=7.0
  • ext-pcntl: *
  • ext-posix: *
  • ext-json: *
  • ext-mbstring: *


安装

linux:composer require mojiehai/process_manage

windows:composer require mojiehai/process_manage --ignore-platform-reqs (windows下仅安装,不支持使用)



使用

  1. 启动
    
    $config = [
        // 进程基础配置
        'titlePrefix' => 'process_m',   // 进程前缀
        'baseTitle' => 'test',  // 进程基础名称
    
        // master 进程配置
        'checkWorkerInterval' => 0,    // n秒检测一次进程(<=0则为不检测)
        'maxWorkerNum' => 1,    //1个进程
    
        // worker 进程配置
        'executeTimes' => 1,    // 任务的最大执行次数(0为没有最大执行次数,一直执行)
        'executeUSleep' => 10000000,  // 每次执行任务睡眠时间(微秒) 1s = 1 000 000 us (1s)
        'limitSeconds' => 10800,    // 工作进程最大执行时长(秒)(跑3个小时重启)
    ];
    
    try {
        // 创建进程管理器
        (new Manage($config))
            ->setWorkInit(
                // 工作内容初始化
                function (Process $process) {
                    // init
                    \ProcessManage\Log\ProcessLog::Record('info', $process, 'work init ... ');
                }
            )
            ->setWork(
                // 执行的工作内容
                function(Worker $process) {
                    // work
                    \ProcessManage\Log\ProcessLog::Record('info', $process, 'work run ... ');
                })
            ->start();
    } catch (ProcessException $e) {
        echo $e->getExceptionAsString();
    }

  1. 停止
    
    $config = [
        // 进程基础配置
        'baseTitle' => 'test',  // 进程基础名称
    ];
    
    try {
        // 创建进程管理器
        (new Manage($config))->stop();
    } catch (ProcessException $e) {
        echo $e->getExceptionAsString();
    }

  1. 平滑重启
    
    $config = [
        // 进程基础配置
        'titlePrefix' => 'process_m',   // 进程前缀
        'baseTitle' => 'test',  // 进程基础名称
    
        // master 进程配置
        'checkWorkerInterval' => 0,    // n秒检测一次进程(<=0则为不检测)
        'maxWorkerNum' => 1,    //1个进程
    
        // worker 进程配置
        'executeTimes' => 1,    // 任务的最大执行次数(0为没有最大执行次数,一直执行)
        'executeUSleep' => 10000000,  // 每次执行任务睡眠时间(微秒) 1s = 1 000 000 us (1s)
        'limitSeconds' => 10800,    // 工作进程最大执行时长(秒)(跑3个小时重启)
    ];
    
    try {
        // 创建进程管理器
        (new Manage($config))
            ->setWorkInit(
                // 工作内容初始化
                function (Process $process) {
                    // init
                    \ProcessManage\Log\ProcessLog::Record('info', $process, 'work init ... ');
                }
            )
            ->setWork(
                // 执行的工作内容
                function(Worker $process) {
                    // work
                    \ProcessManage\Log\ProcessLog::Record('info', $process, 'work run ... ');
                })
            ->setBackground()->restart();
    } catch (ProcessException $e) {
        echo $e->getExceptionAsString();
    }

  1. 查看信息
     
    $config = [
        // 进程基础配置
        'baseTitle' => 'test',  // 进程基础名称
    ];
    
    try {
        // 创建进程管理器
        (new Manage($config))->showStatus();
    } catch (ProcessException $e) {
        echo $e->getExceptionAsString();
    }

注意:baseTitle(进程基础名称)为进程的标识,start/stop/restart/status指定的名称必须相同。



说明

  1. 参数说明
    1. 固定配置(通过Config类的子类加载,作用域为全局,可在业务入口文件中指定)。例如ProcessConfig::LoadConfig(["TitlePrefix" => "test"])

      • 进程配置,通过ProcessConfig::LoadConfig($configArray)加载,配置项如下:

        配置项 描述 类型 默认值
        PidRoot 存放master进程pid文件根目录 string /tmp/pm/pid
        TitlePrefix 进程名称前缀 string process_m
        StatusFileRoot 存放进程状态文件根目录 string /tmp/pm/status
      • 日志配置,通过LogConfig::LoadConfig($configArray)加载,配置项如下:

        配置项 描述 类型 默认值
        ENABLED 是否启动日志 boolean true
        LogBaseRoot 日志文件根目录 string process_manage/runtime/log
        Debug_FileNamePrefix debug日志级别对应的文件名前缀 string
        Info_FileNamePrefix info日志级别对应的文件名前缀 string
        Notice_FileNamePrefix notice日志级别对应的文件名前缀 string
        Warning_FileNamePrefix warning日志级别对应的文件名前缀 string
        Error_FileNamePrefix error日志级别对应的文件名前缀 string error_
        Fatal_FileNamePrefix fatal日志级别对应的文件名前缀 string fatal_
        LogFileName 普通日志文件默认文件名 string run
        LogDeLimiterRule 普通日志文件分隔规则,默认按天分隔 string Y-m-d
        ProcessLogFileName 进程日志文件默认文件名 string process
        ProcessLogDeLimiterRule 进程日志文件分隔规则,默认按天分隔 string Y-m-d
    2. 非固定配置(通过manage构造函数加载进去,作用域为本次manage管理的进程)

      配置项 描述 类型 是否必填 默认值
      titlePrefix 进程名称前缀,优先级大于固定配置 string (默认读取固定配置值)
      baseTitle 进程基础名称,用来区分多个进程管理器 string process
      checkWorkerInterval master:检查工作进程的时间间隔,单位:秒 int 300
      maxWorkerNum master:最大工作进程数 int 4
      executeTimes worker:工作进程最大工作次数(即工作回调最大回调次数) 0为无限循环执行,(执行完指定次数后退出子进程,等待master进程重启子进程) int 1
      executeUSleep worker:工作进程每次执行后睡眠时间 单位:微秒数 0为不睡眠 int 200000
      limitSeconds worker:工作进程最大执行时长 单位:秒 0为不限制(执行完指定次数后退出子进程,等待master进程重启子进程) int 0

  1. 方法说明
    • Manage类(单任务多进程管理器)

      方法名 参数说明 返回值 描述
      setBackground() Manage 设置为后台运行,该方法执行完毕后,当前进程就会脱离终端,成为init进程的子进程。
      setWorkInit(\Closure $closure = null) $closure:回调函数 Manage 设置工作进程初始化的回调方法,这个回调方法会在worker进程对象初始化完成后调用。一般该回调方法中初始化一些资源数据,例如数据库连接,给当前worker进程的工作回调使用。该回调方法接收一个参数,为当前的worker进程对象(Worker)。(示例见 1.0 )
      setWork(\Closure $closure = null) $closure:回调函数 Manage 设置工作进程工作回调,该回调会在setWorkInit设置的初始化回调后调用。该回调方法接收两个参数:第一个为当前的worker进程对象(Worker),第二个为工作进程初始化的回调方法的返回值。(示例见 1.1 )
      start() 启动任务
      stop() 停止任务
      restart() 重启任务
      status() array 进程状态数组
      showStatus() array $status: 状态数组(status()的返回值) 格式化显示进程状态信息 (说明见 1.2 )
    • ManageMultiple类(多任务多进程管理器)

      方法名 参数说明 返回值 描述
      addManage() Manage $manage: 单任务管理器 添加管理器
      removeManage() String $baseTitle: 进程的基础名称 删除管理器
      getManage() String $baseTitle: 进程的基础名称 Manage 获取单个进程管理器
      start() 启动任务
      stop() 停止任务
      restart() 重启任务
      status() array 进程状态数组
    • Process类

      方法名 参数说明 返回值 描述
      resetPid() 重设pid(不需要手动调用)
      setWorkInit(\Closure $closure = null) $closure:回调函数 Process 设置工作初始化回调(不需要手动调用)
      setWork(\Closure $closure = null) $closure:回调函数 Process 设置工作回调(不需要手动调用)
      setStop() 给当前进程对象发送停止信号
      isExpectStop() bool 判断当前进程是否准备停止
      isRun() 判断当前进程是否为正在运行状态
      run() 开始运行(不需要手动调用)
      isAlive() bool 检测当前进程对象是否存在
      static CheckAlive(int $pid) $pid:进程pid bool 检测进程是否存在
    • Worker类(继承Process类)

      方法名 参数说明 返回值 描述
      getExecuteTimes() int 获取当前执行次数
    • Master类(继承Process类)

      方法名 参数说明 返回值 描述
      getAllStatus() array 获取所有进程状态信息

  1. 示例或说明
    • 1.0
       (new Manage($config))->setWorkInit(
           // 工作内容初始化
           function (Worker $process) {
       	// init
       	$link = mysqli_connect(...);
       	...
       	$redis = new Redis(...);
       	...
       	return ['mysql' => $link, 'redis' => $redis];
           }
        )
    • 1.1
       (new Manage($config))->setWork(
           // 执行的工作内容
           function(Worker $process, $result = []) {
       	// work
       	$mysqlLink = $result['mysql'];
       	$redisLink = $result['redis'];
           })
        )
    • 1.2
       [root@localhost command]# php cmd.php status
       Master
         type      pid      title                    memory(m)         start                  run(s)    count
         Master    29570    process_m:Master:test    0.661(693296b)    2018-12-23 17:29:01    6         2           
      
       Worker
         type      pid      title                    memory(m)         start                  run(s)    work
         Worker    29571    process_m:Worker:test    0.661(692760b)    2018-12-23 17:29:01    6         1         
         Worker    29572    process_m:Worker:test    0.661(693608b)    2018-12-23 17:29:01    6         1         
      
      字段说明:(Master表示主进程,Worker表示工作进程)
      • type:进程类型说明(Master/Worker)
      • pid:进程pid
      • title:进程名称
      • memory:内存消耗,单位:M,括号中的为字节数
      • start:进程开始时间
      • run:运行时长,单位:秒
      • count:(Master进程独有属性)当前子进程个数
      • work:(Worker进程独有属性)当前进程执行任务回调的次数


命令管理

提供了一套命令管理的方案,通过实现部分接口即可接入

  1. 简述
    该方案为自定义命令,但是有部分预定义命令。
    • 预定义命令:所有命令均有的基本行为,权重最高。预定义命令列表如下:
      • --help: 查看命令列表
    • 自定义命令:分为两个部分,一部分为行为参数(必填参数),一部分为附加参数(选填参数)。(需要定义模板)
      一条命令由一个明确的行为参数确定行为动作,若干个附加参数附带其他信息配置等。
      例如:start -d 行为参数为start,表示启动,附加参数d,表示后台运行

  1. 命令模板
    • 格式:
      • <>包裹着为必填参数(行为参数),参数可选值用 | 分隔
      • []包裹着为选填参数(附加参数),参数可选值用 | 分隔
      • 附加参数前缀必须带上-
    • 注意事项:
      • 行为参数只能有一个,且只能在最前面一项
      • 附加参数可以有多个,在行为参数后面
      • 输入命令时,每个附加参数可以连上=号传递想输入的参数
    • 例如:<start|stop|restart> -[d] -[a|s]

  1. 构建命令
    1. 创建行为动作类继承ProcessManage\Command\Action类,并实现下列方法:(一个行为动作一个类)

      • handler()
        执行该命令的动作
      • getCommandStr()
        返回命令字符串
      • getCommandDescription()
        返回命令描述
    2. 创建附加参数类继承ProcessManage\Command\Options类,并实现下列方法:(一个附加参数一个类)

      • getCommandStr()
        返回命令字符串
      • getCommandDescription()
        返回命令描述
      • impactAction(Action $action)
        影响action的行为方式,建议在这个方法中使用$action->setParam('key', 'value');给action设置参数,然后在action类的handler方法中通过$this->getParam($key)获取参数,进行操作。例如:
        /**
         * 影响action的行为
         * @param Action $action
         * @return mixed
         */
        public function impactAction(Action $action)
        {
            // $this->param 存储了用户输入的这个附加参数所带的值
            $action->setParam('runInBackground', true);
        }
    3. 创建模板类继承ProcessManage\Command\Template类,并实现下列内容:(一个命令一个模板)

      • $mapping
        命令映射关系(把action、options映射到具体的类),例如:
        /**
         * 命令映射的类
         * @var array
         */
        public $mapping = [
            'action' => [
                'start' => '\ProcessManage\Command\Action\Start',
                'stop' => '\ProcessManage\Command\Action\Stop',
                'restart' => '\ProcessManage\Command\Action\ReStart',
            ],
            'options' => [
                'd' => '\ProcessManage\Command\Options\D',
            ],
        ];
      • getTemplateStr()
        定义模板格式,例如:
        /**
         * 获取模板内容
         * @return string
         */
        public function getTemplateStr()
        {
            return '<start|stop|restart> -[d]';
        }

  1. 使用
    use ProcessManage\Command\Command;
    use ProcessManage\Command\Template\ManageProcessTemplate;
    
    $command = new Command(new ManageProcessTemplate());
    $command->run();

  1. 运行
    [root@localhost command]# php cmd.php --help
    Usage: <start|stop|restart|status> -[d]
    action: 
      start         start process
      stop          stop process
      restart       restart process
      status        process status
    options: 
      -d            background running process
    other: 
      --help        to display the list of available commands, please use the list command.