wapmorgan / system-daemon
系统守护进程的简单基础
Requires
- ext-pcntl: *
- ext-posix: *
This package is auto-updated.
Last update: 2024-09-16 11:13:07 UTC
README
系统守护进程的简单基础。
为什么你需要SystemDaemon?
- 你想要创建一个守护进程(后台运行的进程)并能够管理它
- 你想要去除项目中不必要的依赖
- 你不想编写这样的守护进程基础
如果以上三个条件都适合你,SystemDaemon
将满足你所有的需求。
创建自己的守护进程需要什么
- 创建一个继承自
AbstractDaemon
的类,并实现后台工作所需的方法 - 运行此类的实例或使用
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
提供的主要功能
- 在后台启动守护进程。通过锁文件禁止运行多个守护进程副本。
- 创建日志文件并将其消息写入其中。
- 守护进程可以是两种类型:普通守护进程(其中
onStart()
方法启动一次并完成所有工作)和定时唤醒的守护进程(称为“tick”)并执行onTick()
方法。
守护进程的类型
创建的守护进程可以在两种模式下工作
- 普通模式。当一个方法启动并处理一些外部数据(例如,监听套接字)时,此模式默认使用。要创建守护进程,您需要重写
onStart()
方法,该方法将在守护进程启动时调用。例如,这样
class MyDaemon extends AbstractDaemon { protected function onStart() { // here's your daemon's code } }
- 定时模式。当守护进程在固定间隔醒来时,它会获取一些信息,执行其任务,然后进入休眠状态,直到下一次“滴答”。要使用此模式,您需要在创建类实例时传递
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 } }
停止
停止处理其自身的每种类型
- 一个普通的守护进程在
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 } } }
- 定时守护进程更容易使用:它将继续滴答,直到接收到 停止 命令。因此,您不需要手动处理此操作。守护进程将在接收到此命令的滴答处理时结束。
其他信号
您有权处理由 kill 命令发送的其他信号。目前,可以处理两个信号,可以用作缓冲区重置命令、清除缓存或进行其他操作。这些命令是:SIGUSR1
和 SIGUSR2
。要在守护进程中处理它们,分别重新实现 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)
方法。支持两种类型的日志记录
- 向 syslog 日志记录。使用示例
$daemon = new AbstractDaemon(); $daemon->setLogger(AbstractDaemon::SYSLOG);
- 向单独的文件记录日志。要启用在单独的文件中的日志记录(/var/log/daemon-守护进程名称.log,如果权限允许,或 /tmp/daemon-名称.log)
$daemon = new AbstractDaemon(); $daemon->setLogger(AbstractDaemon::FILES);
- 向终端记录日志。守护进程将直接在终端打印所有日志消息
$daemon = new AbstractDaemon(); $daemon->setLogger(AbstractDaemon::TERMINAL);
要在守护进程中将消息发送到日志,请使用 log($level, $message)
方法,其中 $level
是预定义的消息严重级别之一,而 $message
是消息。
预定义的重要性级别
AbstractDaemon::ERROR
AbstractDaemon::WARNING
AbstractDaemon::NOTICE
AbstractDaemon::INFO
AbstractDaemon::DEBUG