zlikavac32/alarm-scheduler

0.2.1 2019-04-25 19:13 UTC

This package is auto-updated.

Last update: 2024-09-29 05:28:11 UTC


README

Build Status

这个库为多个 SIGALRM 处理器提供支持。

目录

  1. 介绍
  2. 安装
  3. API
    1. AlarmHandler
    2. AlarmScheduler
    3. InterruptException
    4. InterruptAlarmHandler
    5. CatchThrowableAlarmHandler
  4. 使用方法
  5. 经验法则
  6. 示例

介绍

从 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 之外,不应该从警报处理器中抛出异常。如果抛出了异常,并且调度器实现没有捕获它(这不是要求),可能会导致调度器处于不一致的状态。

如果需要自定义异步异常,另一种选择是使用 SIGUSR1SIGUSR2 在不同的堆栈帧中抛出异常。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 目录中找到。