进程组件
Swoft 框架中封装了一套经常操作方式,替换 PHP 的 pcntl
,PHP 自带的 pcntl
,存在很多不足,如:
pcntl
没有提供进程间通信的功能pcntl
不支持重定向标准输入和输出pcntl
只提供了fork
这样原始的接口,容易使用错误
安装
Swoft 基于 Swoole 进程操作封装,功能与 Swoole 完全一样,建议开发者使用 Swoft 的封装操作,方便框架一起迭代升级。2.0.4+ 支持且需要安装 swoft-process
组件
composer require swoft/process
方法列表
所有操作在方法,全部在 Swoft\Process\Process
里面
new
__construct
start
name
exec
write
read
setTimeout
setBlocking
useQueue
statQueue
freeQueue
exportSocket
push
pop
close
exit
kill
wait
daemon
signal
alarm
setAffinity
用户进程
Http/RPC/Websocket/TCP
等服务有些业务场景,需要一个后台运行进程去监控、上报或者其它特殊操作,此时可以在相应服务启动的时候,添加一个用户自定义工作进程,来实现。 自定义用户进程与服务一起启动,服务关闭一起退出,如果自定义用户进程被意外关闭,服务会重新启动一个新的自定义用户进程,保证自定义用户进程一直存在。
2.0.4+ 支持且需要安装 swoft-process 组件
声明用户进程
使用自定义用户进程之前,必须定义用户进程,如下定义一个监控上报信息的用户进程为例:
示例: 自定义用户进程入口。
<?php declare(strict_types=1);
namespace App\Process;
use App\Model\Logic\MonitorLogic;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Bean\Annotation\Mapping\Inject;
use Swoft\Db\Exception\DbException;
use Swoft\Process\Process;
use Swoft\Process\UserProcess;
/**
* Class MonitorProcess
*
* @since 2.0
*
* @Bean()
*/
class MonitorProcess extends UserProcess
{
/**
* @Inject()
*
* @var MonitorLogic
*/
private $logic;
/**
* @param Process $process
*
* @throws DbException
*/
public function run(Process $process): void
{
$this->logic->monitor($process);
}
}
- 自定义用户进程必须实现
Swoft\Process\UserProcess
接口 - 自定义用户进程必须使用
@Bean
标记为一个bean
对象
示例: 业务处理。
<?php declare(strict_types=1);
namespace App\Model\Logic;
use App\Model\Entity\User;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Db\Exception\DbException;
use Swoft\Log\Helper\CLog;
use Swoft\Process\Process;
use Swoft\Redis\Redis;
use Swoole\Coroutine;
/**
* Class MonitorProcessLogic
*
* @since 2.0
*
* @Bean()
*/
class MonitorLogic
{
/**
* @param Process $process
*
* @throws DbException
*/
public function monitor(Process $process): void
{
$process->name('swoft-monitor');
while (true) {
$connections = context()->getServer()->getSwooleServer()->connections;
CLog::info('monitor = ' . json_encode($connections));
// Database
$user = User::find(1)->toArray();
CLog::info('user='.json_encode($user));
// Redis
Redis::set('test', 'ok');
CLog::info('test='.Redis::get('test'));
Coroutine::sleep(3);
}
}
}
自定义用户进程里面,开发者必须实现类似 while(true)
的业务,且里面可以直接使用 Swoft 封装好的所有IO操作,比如数据库、缓存、RPC,以及其它非 Swoft 封装的协程操作配置
定义好了用户进程,必须配置才会有效,Http/RPC/Websocket/TCP
服务配置自定义进程都一样,这里以如上自定义的用户进程配置为例:
return [
'httpServer' => [
'class' => HttpServer::class,
'port' => 18306,
'listener' => [
'rpc' => bean('rpcServer')
],
'process' => [
'monitor' => bean(MonitorProcess::class)
],
// ...
],
];
这里以注入的方式配置了一个自定义用户进程,名称为 monitor
。
如果配置成功,服务启动后,用户进程里面的业务会自动执行,无需其它操作。
进程池
进程池一般用于需要程序一直运行的场景,比如队列消费,数据计算。Swoft 框架中,基于 Swoole 进程池模型再次封装,便于开发者快速简单的使用进程池。
2.0.4+ 支持且需要安装
swoft-process
组件。
进程池配置
组件安装成功后,默认不需要配置也可以使用,配置如下:
app/bean.php
return [
'processPool' => [
'class' => \Swoft\Process\ProcessPool::class,
'workerNum' => 3
]
];
workerNum
worker 进程数ipcType
IPC类型coroutine
是否开启协程,默认是开启
@Process 注解
@Process
标记类是一个进程池处理流程
属性列表:
workerId
int|array 绑定的进程ID,可以使单个或者数组。默认情况,是绑定到其它未绑定的进程。
声明工作进程
配置好之后,就是声明工作进程。如下已 workerNum =3
,定义三个 worker
进程为例:
worker 进程1:
<?php declare(strict_types=1);
namespace App\Process;
use Swoft\Log\Helper\CLog;
use Swoft\Process\Annotation\Mapping\Process;
use Swoft\Process\Contract\ProcessInterface;
use Swoole\Coroutine;
use Swoole\Process\Pool;
/**
* Class Worker1Process
*
* @since 2.0
*
* @Process(workerId=0)
*/
class Worker1Process implements ProcessInterface
{
/**
* @param Pool $pool
* @param int $workerId
*/
public function run(Pool $pool, int $workerId): void
{
while (true) {
CLog::info('worker-' . $workerId);
Coroutine::sleep(3);
}
}
}
worker
进程必须实现Swoft\Process\Contract\ProcessInterface
接口- 开发者业务必须自己实现类似
while(true)
逻辑 @Process
注解workerId=0
表示第1个进程绑定这个处理逻辑流程
worker 进程2和进程3:
<?php declare(strict_types=1);
namespace App\Process;
use App\Model\Entity\User;
use Swoft\Db\Exception\DbException;
use Swoft\Log\Helper\CLog;
use Swoft\Process\Annotation\Mapping\Process;
use Swoft\Process\Contract\ProcessInterface;
use Swoft\Redis\Redis;
use Swoole\Coroutine;
use Swoole\Process\Pool;
/**
* Class Worker2Process
*
* @since 2.0
*
* @Process(workerId={1,2})
*/
class Worker2Process implements ProcessInterface
{
/**
* @param Pool $pool
* @param int $workerId
*
* @throws DbException
*/
public function run(Pool $pool, int $workerId): void
{
while (true) {
// Database
$user = User::find(1)->toArray();
CLog::info('user='.json_encode($user));
// Redis
Redis::set('test', 'ok');
CLog::info('test='.Redis::get('test'));
CLog::info('worker-' . $workerId.' context='.context()->getWorkerId());
Coroutine::sleep(3);
}
}
}
worker
进程必须实现Swoft\Process\Contract\ProcessInterface
接口- 开发者业务必须自己实现类似
while(true)
逻辑 @Process
注解workerId={1,2}
表示第2个进程和第3个进程,同时绑定这个处理逻辑流程
启动进程池
配置和声明工作进程完成后,就是启动进程池,启动进程池和其它服务启动很类似
前台启动
php bin/swoft process:start
后台启动
bin/swoft process:start -d
2019/07/16-09:44:34 [INFO] Swoft\SwoftApplication:setSystemAlias(496) Set alias @base=/data/www/swoft
... ...
2019/07/16-09:44:44 [INFO] Swoft\Processor\ConsoleProcessor:handle(39) Console command route registered (group 13, command 40)
重启所有 worker 进程
php bin/swoft process:reload
2019/07/16-09:45:52 [INFO] Swoft\SwoftApplication:setSystemAlias(496) Set alias @base=/data/www/swoft
... ...
2019/07/16-09:45:59 [INFO] Swoft\Processor\ConsoleProcessor:handle(39) Console command route registered (group 13, command 40)
Server bin/swoft is reloading
Process pool bin/swoft reload success
停止服务
php bin/swoft process:stop
2019/07/16-09:46:35 [INFO] Swoft\SwoftApplication:setSystemAlias(496) Set alias @base=/data/www/swoft
... ...
2019/07/16-09:46:45 [INFO] Swoft\Processor\ConsoleProcessor:handle(39) Console command route registered (group 13, command 40)
Stopping .. Successful!