zlikavac32 / alarm-scheduler
SIGALRM 调度器
Requires
- php: ^7.1
- ext-pcntl: *
- php-ds/php-ds: ^1.2
Requires (Dev)
- phpspec/phpspec: ^5.1
- phpunit/phpunit: ^7.5
Suggests
- ext-ds: Native php-ds implementation
This package is auto-updated.
Last update: 2024-09-29 05:28:11 UTC
README
这个库为多个 SIGALRM
处理器提供支持。
目录
介绍
从 PHP 7.1 开始,异步信号通过 pcntl_async_signals() 函数支持。有了这个功能,pcntl_alarm() 变得更有帮助。
唯一的问题是,我们只能为每个进程设置一个信号处理器。
这个库提供了一个简单的 SIGALRM
调度器,允许通过一些任意延迟安排多个目标。
安装
推荐通过 Composer 安装。
composer require zlikavac32/alarm-scheduler
API
提供了两个接口,一个用于警报处理器,另一个用于警报调度器。
请注意,这个库不会调用 pcntl_async_signals(true);
。调用者负责在其认为适用的地方调用它。
AlarmHandler
接口 \Zlikavac32\AlarmScheduler\AlarmHandler
用于实现警报处理器。方法 handle()
将从信号处理器中调用,有关更多信息,请参阅 经验法则。
将当前调度器传递给 handle()
,以便重新调度处理器(或安排一个新的处理器)。
AlarmScheduler
接口 \Zlikavac32\AlarmScheduler\AlarmScheduler
用于实现警报调度器。实现应控制 SIGALRM
的处理。
方法必须安全地从信号处理器内部调用。有关更多信息,请参阅 经验法则。
InterruptException
表示必须由调度器实现尊重的硬中断的异常。
它可以从警报处理器抛出,以从信号处理器中引发异常。
用户在 经验法则 部分描述的硬中断中不受此异常的限制。
InterruptAlarmHandler
通过抛出 InterruptException
从警报调度器引发硬中断
CatchThrowableAlarmHandler
\Zlikavac32\AlarmScheduler\CatchThrowableAlarmHandler
实现了一个封装任何其他警报处理器并捕获从其中捕获的所有可抛出的警报处理器。捕获的内容传递到 \Zlikavac32\AlarmScheduler\ThrowableHandler
。如果可抛出处理程序抛出任何内容,则将其静默忽略。
通过 \Zlikavac32\AlarmScheduler\IgnoreThrowableHandler
提供了一个简单的可抛出处理程序,它只忽略所有内容。
使用方法
首先创建调度器(目前只提供了一个实现)。
$scheduler = new \Zlikavac32\AlarmScheduler\NaiveAlarmScheduler();
当需要接管 SIGALRM
处理时,调用
$scheduler->start();
必须在调用调度器方法的任何其他使用之前调用 start()
方法。
然后实现一些警报处理器。
$handler = new class implements \Zlikavac32\AlarmScheduler\AlarmHandler { public function handle(\Zlikavac32\AlarmScheduler\AlarmScheduler $scheduler): void { echo (new DateTime())->format('i\\m:s\\s'), "\n"; } };
接下来,安排警报处理器。
$scheduler->schedule(5, $handler); // to run $handler in 5 seconds
现在,这不会阻塞。如果脚本在处理器被触发之前达到末尾,它将退出而不触发它们。
为了测试目的,我们可以暂停几秒钟。我们还可以打印当前时间。
echo (new DateTime())->format('i\\m:s\\s'), "\n"; $sleep = 7; while ($sleep = sleep($sleep));
经验法则
如果 SIGALRM
没有被阻塞,它可以在任何时刻中断调度方法。调度器的实现必须能够在信号处理器中安全运行。在大多数情况下,这意味着在调度方法完成之前阻塞信号,然后再解阻塞它。PHP 虚拟机负责处理其余部分。
除了 \Zlikavac32\AlarmScheduler\InterruptException
之外,不应该从警报处理器中抛出异常。如果抛出了异常,并且调度器实现没有捕获它(这不是要求),可能会导致调度器处于不一致的状态。
如果需要自定义异步异常,另一种选择是使用 SIGUSR1
或 SIGUSR2
在不同的堆栈帧中抛出异常。PHP 虚拟机将延迟信号处理,直到当前处理器完成。这意味着它不会影响调度器的堆栈帧。
pcntl_signal(SIGUSR1, function (): void { throw new SomeDomainSpecificException(); }); $scheduler->schedule(2, new class implements \Zlikavac32\AlarmScheduler\AlarmHandler { public function handle(\Zlikavac32\AlarmScheduler\AlarmScheduler $scheduler): void { posix_kill(getmypid(), SIGUSR1); } });
在 SIGALRM
下使用 sleep()
可能不安全,因此在使用此库之前请检查您的系统如何处理休眠。
示例
带有代码注释的示例可以在 examples 目录中找到。