`<?php
use Swoole\Coroutine\Channel;
use Swoole\Process;
class MyProcess
{
protected $chan;
protected $client;
private $swooleProcess;
private $processName;
private $async = null;
private $args = [];
final function __construct(string $processName,array $args = [],$async = true)
{
$this->async = $async;
$this->args = $args;
$this->processName = $processName;
$this->swooleProcess = new \swoole_process([$this,'__start']);
}
public function getProcess():Process
{
return $this->swooleProcess;
}
function __start(Process $process)
{
if(PHP_OS != 'Darwin'){
$process->name($this->getProcessName());
}
if (extension_loaded('pcntl')) {
pcntl_async_signals(true);
}
$this->run($this->swooleProcess);
}
public function getProcessName()
{
return $this->processName;
}
public function run(Process $process)
{
$this->addTick(2000,function(){
\go(function (){
echo "\n\nCurrent Coroutine id is : ".\Swoole\Coroutine::getuid() . "\n";
//直接运行代码,没有写捕获异常逻辑
$this->runSomeCode();
});
});
}
public function addTick($ms,callable $call):?int
{
return self::loop(
$ms,$call
);
}
public static function loop($microSeconds,callable $func,$args = null){
global $server;
$new = function (...$args)use($func){
try{
call_user_func($func,...$args);
}catch (\Throwable $throwable){
echo $throwable->getMessage();
}
};
return $server->tick($microSeconds,$new,$args);
}
//执行逻辑代码
protected function runSomeCode()
{
//正常逻辑代码
try {
//定时执行,easyswoole的AbstractPool类有定时回收闲置连接池,测试代码只是模拟一下问题,定位是这里如果逻辑出现一次错误后,此处后面执行就会频繁报错\Swoole\Coroutine\Channel::pop(): must be called in the coroutine.
swoole_timer_tick(2000,function(){
echo "pop from channel\n";
$this->chan->pop();
});
$this->getPool();
mt_srand();
//随机一次抛出异常
$rand = mt_rand(1,3);
echo "current rand is : ".$rand."\n";
//此处是为了模拟多次情况下,其中某一次不正常的情况
if ($rand != 3) {
var_dump('execute some logic');
} else {
throw new \Exception("some error");
}
} catch (\Throwable $throwable) {
throw $throwable;
}
}
protected function getPool()
{
$this->chan = new Channel(5);
$this->chan->push('test');
return $this->chan->pop();
}
}
$server = new \Swoole\Server('127.0.0.1', '9501', SWOOLE_PROCESS, SWOOLE_SOCK_UDP);
$server->set([
'log_file' => '/tmp/swoole.log',
// 'daemonize'=> 1
]);
$server->on('packet', function () { });
$server->addProcess((new MyProcess('test'))->getProcess());
$server->start();
?>
`
说明:
1.这里的代码,只是精简摘写部分easyswoole框架的代码
如果捕获抛出的异常(easyswoole连接超时会抛一个异常),不会有这种问题,但如果代码层级很深,很复杂的逻辑有遗漏捕获异常的情况下,而且逻辑里面有定时逻辑,每次定时执行时就出现这种问题,只能重新启动server了;
提这个issue,主要是想排查是不是因为swoole_time_tick由于没有捕获异常,而导致后续持续报这种Fatal error: Swoole\Coroutine\Channel::pop(): must be called in the coroutine.这种错误