为了账号安全,请及时绑定邮箱和手机立即绑定

从零开发一个监听信号的包

标签:
PHP Docker laravel

引言

本文通过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
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消