在选定swoole作为PHP微服务的底层以后,我找了很久swoole server端的超时控制,但是,swoole的官方文档里,没有写server端的超时控制(类似于php-fpm的request_terminate_timeout配置),swoole源码里的example写了
examples/process/func_timeout.php
declare(ticks = 1);
Swoole\Async::set([
'enable_signalfd' => false,
]);
class FunctionTimeoutException extends RuntimeException
{
}
function test()
{
sleep(1);
}
$serv = new Swoole\Http\Server("127.0.0.1", 9502);
$serv->set(['worker_num' => 1]);
$serv->on('WorkerStart', function($serv, $workerId) {
pcntl_signal(SIGALRM, function () {
Swoole\Process::alarm(-1);
throw new FunctionTimeoutException;
});
});
$serv->on('Request', function($request, $response) {
try
{
Swoole\Process::alarm(100 * 1000);
test();
Swoole\Process::alarm(-1);
$response->end("
Finish
");}
catch(FunctionTimeoutException $e)
{
$response->end("
Timeout
");}
});
$serv->start();
但是这个用法有个地方要注意,它依赖系统信号SIGALRM,而PHP处理系统信号,依赖
declare(ticks = 1)
而且是每一个文件的头部都要加上这句代码,require和include都不行(后面加上once也不行)。
我刚开始写基础框架的时候,没有注意到这一点,然后上线查看日志的时候,发现,明明timeout设置的为1000ms,为毛日志里没有超过1000ms的超时日志,然后才意识每个文件都要加上declare(ticks = 1),测下来也确实如此,虽然很恶心,但是也没办法。
但是,在PHP升级到PHP 7.1 之后,就不用写这个了
只需要在框架入口处加上
pcntl_async_signals(true);
或者修改php.ini
pcntl.async_signals = 1
这样就完美了。
更多架构、PHP、GO相关踩坑实践技巧请关注我的公众号:PHP架构师