如何在 PHP 中对 Unix 信号处理进行可靠的集成测试?

How to do reliable integration testing of Unix signal handling in PHP?

我正在编写一个 运行 在后台运行的服务器系统。用非常简单的术语来说,它有自己的脚本语言,这意味着一个进程可以用该语言编写成 运行 自己,或者它可以调用另一个进程,等等。我正在将这个系统从一个微不足道的 PHP cron-job,其中一次只允许一个实例到一组由 Supervisor 管理的 long-运行ning 进程。

考虑到这一点,我知道这些进程可以随时终止,无论是在开发过程中由我自己终止,还是由 Supervisord 在停止或重新启动 worker 的正常过程中终止。我想添加一些适当的信号处理以确保工作人员自行整理,并在适当的地方记录任务处于中断状态的位置。

我已经弄清楚如何使用 ticks 和 pcntl_signal() 启用信号处理,目前我的处理似乎工作正常。但是,我想对此进行测试以确保它是可靠的。我已经编写了一些早期的集成测试,但感觉并不那么可靠,主要是因为在开发过程中存在各种奇怪的竞争条件问题,这些问题很难确定。

我想要一些关于如何在 PHP 单元测试中发送 kill 信号的建议或指导,以提高对我的 sig 处理稳健性的信心。我目前的策略:

当然,有了这一切 waiting/checking,它感觉有点粗糙,并且对于各种竞争条件来说已经很成熟了。我目前的感觉是测试将在大约 2% 的时间内失败,但我已经有一天左右无法让测试失败了。我打算做一些浸入式测试,如果我从中遇到任何失败,我会 post 在这里。

我想知道我是否可以通过要求被测系统 kill 本身来简化它,这将删除两级等待检查(一个等待 PID,另一个等待数据库在 kill 命令之前进入正确的状态)。发出 kill 后仍然会离开等待检查循环,但我可能会发现进行一次检查在实践中不是问题。

也就是说,我意识到我的整个方法可能是笨拙的,并且有更好的方法来做这种事情。有任何想法吗?目前我的想法只是增加我的等待超时,以防 PHPUnit 引入任何奇怪的延迟。我也会看看我是否可以得到一个失败案例来检查日志。


† 啊,遗憾的是它不会简化事情。我只是在一个我认为可靠的简单信号集成测试上尝试了这个,并且由于后台 system() returns 立即,它仍然必须循环等待以识别正确的日志记录,然后为正确的post-杀结果。但是,它不再需要等待将 PID 写入临时文件,因此至少消除了一个循环。

正如我在问题中提到的,我尝试的第一个可靠性更改是将工作任务的能力注入 运行 kill 自身。在我的例子中,这是系统内置的,但读者可能会发现编写 child 测试 class 并更改其 DI 配置将是一种方便的方法。

这似乎大大提高了可靠性。原来,测试中有几个等待循环,测试必须在正确的时刻 运行 the kill:

  1. 等待 child 的 PID 可用
  2. 等待 child 日志文件表明它已准备好终止
  3. 发出kill
  4. 等待 child 日志文件正确指示信号处理程序 运行

问题可能出在 (2) - 如果这太短,那么 kill 有时可能会来得太晚,即使找到可靠的最长等待时间,如果 CPU 处于意外负载下,那么它可能仍然容易出现故障。

我现在已经编写了一个快速脚本来重复 运行 PHPUnit 测试,无论是 200 次迭代还是第一次失败,以先到者为准。这现在通过了 200 次迭代,所以暂时我会认为测试可靠性已经上升。但是,如果这种情况发生变化,我会在这里更新 - 也许 运行 高 nice 测试会触发失败。

其他答案仍然是最受欢迎的。