You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactPHP事件循环:并行任务同事务内无法互见数据库变更求助

解决ReactPHP事件循环阻塞导致数据库变更不可见的问题

核心原因

任务2调用的API里的sleep()是同步阻塞函数,会卡住整个ReactPHP事件循环——事件循环在执行任务2的回调时,sleep会持续占用进程,完全没机会执行任务1的futureTick回调。等sleep结束、任务2完成等待逻辑后,任务1才开始执行并写入数据库,自然任务2看不到变更。

解决方案

1. Mock替换同步sleep为异步定时器(优先方案)

既然不能直接修改API里的sleep,就用PHPUnit的Mock功能把这个同步等待换成ReactPHP的异步定时器,让事件循环在等待期间能继续处理其他任务。

假设API里的sleep在JobApi::waitForResult()方法中,测试代码可调整为:

use Mockery;
use React\EventLoop\LoopInterface;

function testXyzScenario() {
    $loop = React\EventLoop\Factory::create();

    // Mock API类,替换sleep为异步定时器
    $jobApi = Mockery::mock(JobApi::class)->makePartial();
    $jobApi->shouldReceive('waitForResult')
        ->andReturnUsing(function ($waitSeconds, LoopInterface $loop, callable $onComplete) {
            // 用ReactPHP定时器替代sleep,不阻塞事件循环
            $loop->addTimer($waitSeconds, function () use ($onComplete) {
                $onComplete(); // 等待结束后执行回调
            });
        });

    $loop->futureTick(function() use ($jobApi) {
        // Task 1: 等待任务2创建作业,写入结果到DB
        // ... DB写入逻辑
    });

    $loop->futureTick(function() use ($jobApi, $loop) {
        // Task 2: 创建作业给任务1,调用Mock后的API等待结果
        // 创建作业逻辑...
        $jobApi->waitForResult(5, $loop, function() {
            // 等待结束后读取DB结果,此时任务1已经写入
            // ... 读取逻辑
        });
    });

    $loop->run();
}

2. 用子进程隔离阻塞操作(备选)

如果没法Mock sleep函数,就把任务2的逻辑放到子进程里执行,子进程的sleep只会阻塞自己,主进程的事件循环能正常处理任务1的回调。

借助react/child-process扩展实现:

use React\ChildProcess\Process;
use React\EventLoop\Factory;

function testXyzScenario() {
    $loop = Factory::create();

    // 任务1:主进程中处理,及时写入DB
    $loop->futureTick(function() {
        // 等待任务2创建作业,写入结果到DB
        // ... DB写入逻辑
    });

    // 任务2:放到子进程执行,sleep不会阻塞主进程事件循环
    $process = new Process('php ' . __DIR__ . '/task2_logic.php');
    $process->start($loop);

    // 监听子进程输出,处理结果
    $process->stdout->on('data', function($data) {
        echo "任务2输出: {$data}";
    });

    $loop->run();
}

task2_logic.php中存放任务2的原始逻辑(包含sleep的API调用),执行完后可将结果输出或写入DB,此时主进程的任务1已提前完成写入,子进程能读到最新数据。

3. 配套优化:使用异步数据库客户端

如果当前用的是同步PDO连接,即使解决了sleep问题,DB操作本身也会阻塞事件循环。建议换成ReactPHP的异步数据库客户端(如react/mysql),让DB操作也异步执行,彻底避免阻塞,提升并行效率。

内容的提问来源于stack exchange,提问作者Amarjit Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:59:59