引言
本文通过composer从零开发一个监听信号的包,并上传到packagist供需要的所有人使用。关于composer是什么以及如何安装等,大家可以去看官方文档:https://www.phpcomposer.com(如果不熟悉信号,可以看我之前的一篇文章《PHP进程通信-进程信号》)
在Github上创建一个项目
这个就不需要介绍了,创建完项目之后,克隆到本地,我这里起名为monitorSignal(我的地址:https://github.com/Rain-Life/monitorSignal)。
创建composer.json
关于composer.json中有哪些参数,以及这些参数的含义,大家可以看官方的文档,对于本文中用到的参数,我会加上注释,文档:https://learnku.com/docs/composer/2018
创建composer.json有两种方式:一种使用composer init命令、一种是手工的方式创建。本文使用第一种方法创建composer.json,在终端上执行composer init命令,按照提示输入即可
此时就可以在项目目录下看到composer.json了,里边的内容如下:
编写代码
编写一个包,一般有以下两个目录:src(必须)、tests(非必须)。
因为此次开发的监听信号量的包,用到了异步监听信号的方法,此方法在PHP7.1之后才引入,所以要求PHP的版本要大于7.1,因此需要对composer.json做如下修改:
因为我在包中添加了信号异常的报警功能,使用到了guzzle来发送企业微信信息,因此需要在包中引入guzzle,执行下边命令进行安装即可:
composer require guzzlehttp/guzzle
执行完之后,会看见生成了一个vender目录
Tip:是不是composer的时候特别卡,推荐阿里云composer全量镜像:
https://developer.aliyun.com/composer?spm=a2c4e.11153940.0.0.40eb6995etnrfP
然后在src中创建MonitorSignal.php,内容如下:
<?php
namespace MonitorSignal;
use GuzzleHttp\RequestOptions;
use GuzzleHttp\Client;
class MonitorSignal
{
const TOKEN = '';//在企业微信群中创建机器人,会生成一个token
const URL = '';//填写自己的接收报警的地址即可
protected $monitorSignal = [];//记录所有监听到的信号
protected $signals = [SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGFPE,
SIGBUS, SIGSEGV, SIGSYS, SIGPIPE, SIGALRM, SIGTERM, SIGURG, SIGTSTP,
SIGCONT, SIGCHLD, SIGTTIN, SIGTTOU, SIGIO, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGUSR1, SIGUSR2
];//其中6和19这两个信号不能被安装信号处理器
public function __construct()
{
pcntl_async_signals(true);//开启异步监听
$this->monitorAny();
}
public function monitor(array $signals) : array
{
$intersect = array_intersect($this->monitorSignal, $signals);
foreach ($intersect as $k=>$v) {
unset($this->monitorSignal[$k]);
}
return $intersect;
}
public function quit()
{
$quitSignalArr = array_intersect($this->monitorSignal, [SIGQUIT, SIGTERM]);
if (!empty($quitSignalArr)) {
//从信号数组中将接收到的信号删掉
foreach ($quitSignalArr as $k=>$v) {
unset($this->monitorSignal[$k]);
}
$this->killSignal();
}
}
public function getSignal() : array
{
return $this->monitorSignal;
}
public function callBackFunc(int $signal)
{
if(!in_array($signal, $this->monitorSignal)) {
$this->monitorSignal[] = $signal;
}
}
public function killSignal()
{
$time = 0;
$totalTime = 0;
while (true) {
sleep(5);
$totalTime+=5;
$content = "<font color='warning'>守护进程报警</font>" . "\n";
$content .= "项目:<font color='warning'>".$_SERVER['APP_NAME']."</font>" . "\n";
$content .= "脚本:<font color='warning'>".$_SERVER['argv'][1]."</font>" . "\n";
$content .= '守护进程'.getmypid().'收到退出(SIGQUIT、SIGTERM)信号,已经过了'.$totalTime.',还未接收到SIGKILL信号';
$this->sendMessage($content, self::TOKEN);
$time++;
if ($time >= config('signal.sleepTimes')) {
break;
}
}
}
//安装所有常用的信号处理器
public function monitorAny()
{
foreach ($this->signals as $signal) {
pcntl_signal($signal, array($this, 'callBackFunc'));
}
}
//发送DingDing消息
public function sendMessage($content, $token='') {
$client = new Client();
$options[RequestOptions::JSON] = [
"msgtype" => "markdown",
"markdown" => [
'content' =>$content
]
];
$uri = self::URL.$token;
$client->request('POST', $uri, $options);
}
}
修改composer.json文件,在里边添加:
"autoload": {
"psr-4": {
"MonitorSignal\\": "src/"
}
}
还没完,这里有个大坑呀,我们需要给我们的这个项目仓库,打一个tag,添加一个tag
如果不添加,我们在后边通过composer安装这个包的时候,会报如下错误:
关于更细节的东西,大家可以参考:
https://learnku.com/php/t/9929/understanding-composers-stability-stability-identity
测试
代码完成之后,对其进行测试。在tests目录下创建一个MonitorSignalTest.php文件,内容如下:
<?php
require '../vendor/autoload.php';
use \MonitorSignal;
$signal = new MonitorSignal\MonitorSignal();
while(true) {
if ($signal->monitor([SIGINT])) {//SIGINT这个信号就是当我们按了Ctrl+C的时候发出的信号
echo "你按了Ctrl+C";
}
sleep(1);
echo "我是业务代码".PHP_EOL;
}
运行上边的代码,可以看到终端中每过1s,输出一句“我是业务代码”,当我们按下Ctrl+C的时候,终端中会输出“你按了Ctrl+C”。此时就大功告成了。
发布到packagist平台
编写完包之后,如果想让更多的人使用,就可以发布到packagist平台上。按照下边步骤进行:
1、将刚才编写好的内容,提交到刚才创建的gitHub仓库中
2、登录到packagist平台(https://packagist.org/),使用gitHub账号登录
3、使用github账号登录之后,在页面中可以看到Submit菜单,点击进去,在【Repository URL (Git/Svn/Hg)】输入框中,放入包的仓库地址:
其实这里还有个问题,如果说我们现在对包的内容进行和修改或完善,难道还要重新在操作一遍?我们肯定是不希望这样的。我们可以在GitHub平台设置代码更新,同时能让 packagist.org自动更新。具体操作如下:
1、进入创建的代码仓库,Setting=>Webhooks
2、在github中,默认是绑定自动更新的,假设没有,我们可以这样做,点击【Add webhook】
- Payload URL填写:“https://packagist.org/api/github”
- Content type填写:“application/json”
- Secret填写:“packagist提供的token”
- 其他的默认即可
- 点击“Add webhook” 完成
以后如果修改此包,就会自动同步到packagist平台上.
如果其它开发者需要使用此包,执行:
composer require rain-life/monitor-signal
下边是这个监听信号的包的github地址,里边会说明使用场景,如果对您有帮助,欢迎给个star _
https://github.com/Rain-Life/monitorSignal