mojiehai/process_manage

1.0.3 2019-01-30 07:36 UTC

README

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.