-
Notifications
You must be signed in to change notification settings - Fork 25
Open
Labels
Description
受影响版本
2.8.6
描述
参考内部代码 CoMessage.php fun>>>yieldByWS
$cid = Coroutine::getuid();
$api_id = ZMAtomic::get('wait_msg_id')->add(1);
$hang['compare'] = $compare;
$hang['coroutine'] = $cid;
$hang['worker_id'] = server()->worker_id;
$hang['result'] = null;
SpinLock::lock('wait_api');
$wait = LightCacheInside::get('wait_api', 'wait_api');
$wait[$api_id] = $hang;
LightCacheInside::set('wait_api', 'wait_api', $wait);
SpinLock::unlock('wait_api');
$id = swoole_timer_after($timeout * 1000, function () use ($api_id) {
$r = LightCacheInside::get('wait_api', 'wait_api')[$api_id] ?? null;
if (is_array($r)) {
Coroutine::resume($r['coroutine']);
}
});
Coroutine::suspend();
SpinLock::lock('wait_api');
$sess = LightCacheInside::get('wait_api', 'wait_api');
$result = $sess[$api_id]['result'] ?? null;
unset($sess[$api_id]);
LightCacheInside::set('wait_api', 'wait_api', $sess);
SpinLock::unlock('wait_api');
swoole_timer_clear($id);
if ($result === null) {
return false;
}
return $result;
由于内部采用 $wait[$api_id] 方式进行存取值 在协程高频情况下 可能会存在丢失部分消息回执的情况(例如go()多机器人调用api,或多机器人群发消息等情况。参见复现方式)
该缓存类使用的是swoole的Table方式 参见官方文档 也警告不要使用数组方式存取数据
该内部类方法在多处均有使用 可能需要修改多处代码 TODO
复现步骤
$all = OneBotV11::getAllRobot();
foreach ($all as $bot) {
$list = $bot->getGroupList();
if ($list === false) {
Console::error('群列表获取失败');
}
foreach ($list['data'] ?? [] as $group) {
$rt = $bot->setPrefix(OneBotV11::API_ASYNC)->sendGroupMsg($group['group_id'],'test');
}
}
封装该群发消息,在多处使用,高频情况下获取群列表可能出现返回false
解决方案
内部缓存使用swoole的Table应避免使用数组方式读写数据,修改局部应用代码为独立Table表 并使用$api_id(参考)为key。
附加信息
No response