wapmorgan/system-daemon

系统守护进程的简单基础

0.0.3 2018-02-26 15:50 UTC

This package is auto-updated.

Last update: 2024-09-16 11:13:07 UTC


README

系统守护进程的简单基础。

Latest Stable Version Latest Unstable Version License

为什么你需要SystemDaemon?

  1. 你想要创建一个守护进程(后台运行的进程)并能够管理它
  2. 你想要去除项目中不必要的依赖
  3. 你不想编写这样的守护进程基础

如果以上三个条件都适合你,SystemDaemon将满足你所有的需求。

创建自己的守护进程需要什么

  1. 创建一个继承自AbstractDaemon的类,并实现后台工作所需的方法
  2. 运行此类的实例或使用DaemonManager

实际上,你可以避免创建新类,而使用基础类来创建守护进程以查看其工作。此外,我们将使用DaemonManager而不是编写处理启动/停止守护进程的用户命令的代码。

DaemonManager处理命令行输入,并运行AbstractDaemon类的必要方法以启动、停止、检查守护进程状态等。

最简单的守护进程,它简单地输出简单的消息到日志

// adjust here path to composer autoloader!
require_once __DIR__.'/../vendor/autoload.php';

use wapmorgan\SystemDaemon\AbstractDaemon;
use wapmorgan\SystemDaemon\DaemonManager;

$daemon = new AbstractDaemon();
$daemon->name = 'example';
$daemon->setLogger(AbstractDaemon::FILES);

(new DaemonManager($daemon))->handleConsole($argc, $argv);

将此文件保存为daemon,并使用php运行它

$ php daemon

你将看到一个简单的帮助列表,列出启动/停止/检查作业状态的合法命令

Manager for daemon "example". Available operations: daemon (start | status | stop | restart | kill)

要启动守护进程,只需用start命令调用相同的脚本。如果成功,将显示启动后的进程ID,可以用来查看此进程的统计信息。

$ php daemon start
Successfully started. Pid is 8868

由于启用了日志记录,你可以打开文件/tmp/daemon-example.log(如果权限允许,则为/var/log/daemon-example.log)并查看守护进程写入的内容

2017-07-28 23:56:40 info: This is a informing message. Reimplement wapmorgan\SystemDaemon\AbstractDaemon::onStart() method to do real work.
2017-07-28 23:56:42 info: This is a informing message. Reimplement wapmorgan\SystemDaemon\AbstractDaemon::onStart() method to do real work.
2017-07-28 23:56:44 info: This is a informing message. Reimplement wapmorgan\SystemDaemon\AbstractDaemon::onStart() method to do real work.
...

这是写入日志的标准占位符消息,除非重新定义了执行所有工作的标准守护进程方法。

如果不使用DaemonManager,则可以使用以下AbstractDaemon的方法来控制守护进程

  • start():返回启动守护进程的进程ID。
  • stop():如果守护进程已停止,则返回true,如果未停止,则返回false,如果未运行,则返回null。此操作比kill()更受青睐,因为可以在守护进程中捕获此操作并正确地完成它。
  • kill():如果守护进程已停止,则返回true,如果未停止,则返回false,如果未运行,则返回null。此操作执行系统终止,仅终止脚本。
  • getStatus():如果守护进程未运行,则返回false,如果正在运行,则返回包含守护进程信息的stdClass对象。

所有这些方法在出现错误时都可以抛出异常(例如,如果无权删除锁文件,或者无权限用户尝试停止由root启动的守护进程),因此请小心处理这些情况。

总结:AbstractDaemon提供的主要功能

  1. 在后台启动守护进程。通过锁文件禁止运行多个守护进程副本。
  2. 创建日志文件并将其消息写入其中。
  3. 守护进程可以是两种类型:普通守护进程(其中onStart()方法启动一次并完成所有工作)和定时唤醒的守护进程(称为“tick”)并执行onTick()方法。

守护进程的类型

创建的守护进程可以在两种模式下工作

  1. 普通模式。当一个方法启动并处理一些外部数据(例如,监听套接字)时,此模式默认使用。要创建守护进程,您需要重写 onStart() 方法,该方法将在守护进程启动时调用。例如,这样
class MyDaemon extends AbstractDaemon
{
    protected function onStart()
    {
        // here's your daemon's code
    }
}
  1. 定时模式。当守护进程在固定间隔醒来时,它会获取一些信息,执行其任务,然后进入休眠状态,直到下一次“滴答”。要使用此模式,您需要在创建类实例时传递 AbstractDaemon::TICKABLE 值以及守护进程唤醒的时间(以秒为单位)。例如。所以
$daemon = new MyDaemon(AbstractDaemon::TICKABLE, 2); // this daemon will "tick" every 2 seconds

要创建这样的守护进程,您需要重写 onTick() 方法,在该方法中指定守护进程在一个滴答内的操作

class MyDaemon extends AbstractDaemon
{
    protected function onTick()
    {
        // here's your daemon's code on every tick
    }
}

停止

停止处理其自身的每种类型

  1. 一个普通的守护进程在 handleStop() 方法中处理停止事件(由 stop() 方法调用)。您可以重写此方法,并在其中关闭一些套接字或设置完成标志,然后在 onStart() 中进行检查:如果设置了标志,则完成数据处理并退出方法。在基类中,handleStop() 将守护进程的 $running 属性设置为 false,因此您可以随时检查该值是否已设置并关闭。例如,您可以这样
class MyDaemon extends AbstractDaemon
{
    protected $fp;

    protected function handleStop()
    {
        fclose($this->fp);
        $this->fp = null;
    }

    protected function onStart()
    {
        $this->fp = fopen('example-file', 'r');
        while (is_resource($this->fp)) {
            // data processing
        }
    }
}
  1. 定时守护进程更容易使用:它将继续滴答,直到接收到 停止 命令。因此,您不需要手动处理此操作。守护进程将在接收到此命令的滴答处理时结束。

其他信号

您有权处理由 kill 命令发送的其他信号。目前,可以处理两个信号,可以用作缓冲区重置命令、清除缓存或进行其他操作。这些命令是:SIGUSR1SIGUSR2。要在守护进程中处理它们,分别重新实现 onSigUsr1()onSigUsr2() 方法。

要使用 USR1 命令重新启动守护进程设置,您可以实施这样的守护进程

class MyDaemon extends AbstractDaemon
{
    protected $config;
    
    protected function onSigUsr1()
    {
        $this->loadConfiguration();
    }
    
    protected function onStart()
    {
        $this->loadConfiguration();
        // ...
    }
    
    protected function loadConfiguration()
    {
        $this->config = json_decode(file_get_contents(__DIR__.'/config.json'));
    }
}

日志记录

您可以使用消息日志。要启用日志记录,必须在创建守护进程对象后调用 setLogger($logger) 方法。支持两种类型的日志记录

  1. 向 syslog 日志记录。使用示例
$daemon = new AbstractDaemon();
$daemon->setLogger(AbstractDaemon::SYSLOG);
  1. 向单独的文件记录日志。要启用在单独的文件中的日志记录(/var/log/daemon-守护进程名称.log,如果权限允许,或 /tmp/daemon-名称.log)
$daemon = new AbstractDaemon();
$daemon->setLogger(AbstractDaemon::FILES);
  1. 向终端记录日志。守护进程将直接在终端打印所有日志消息
$daemon = new AbstractDaemon();
$daemon->setLogger(AbstractDaemon::TERMINAL);

要在守护进程中将消息发送到日志,请使用 log($level, $message) 方法,其中 $level 是预定义的消息严重级别之一,而 $message 是消息。

预定义的重要性级别

  • AbstractDaemon::ERROR
  • AbstractDaemon::WARNING
  • AbstractDaemon::NOTICE
  • AbstractDaemon::INFO
  • AbstractDaemon::DEBUG