Laravel 使用 swoole 协程遇到的坑

最近在用laravel-s改造手头上的一个laravel项目,作为这块目前最火的轮子,确实好用,赞一下作者。由于目前所处理的项目需要调用大量api,使用同步串行调用效率低下,因此开始尝试使用swoole的协程客户端来调用api。

这里我本地的环境如下:

Component Version
PHP 7.1.17
Swoole 2.1.2
Laravel Framework 5.5.40

先来个demo体验一下:

<?php

namespace App\Http\Controllers;

class TestController extends Controller
{
    public function index()
    {
        $cli = new \Swoole\Coroutine\Http\Client('127.0.0.1', 80);
        $cli->setHeaders([
            'Host' => 'test.me',
        ]);
        $cli->get('/');
        $result = $cli->body;
        $cli->close();

        return response()->json($result);
    }
}

启动请求之后发现卡死,这下懵逼了,以前在其他地方都是可以用的协程客户端,这里不能用了,WTF。在群里求助,群主提及到不能在魔术方法和call_user_func之类的方法里使用(官方链接)。一语惊醒梦中人,laravel这个框架可是这类方法横行,于是研究了下Controller类的执行方式。框架在执行Controller时,会通过Illuminate\Routing\Controller类的callAction方法执行具体的Controller类的方法,而这个方法如下:

/**
 * Execute an action on the controller.
 *
 * @param string $method
 * @param array  $parameters
 *
 * @return \Symfony\Component\HttpFoundation\Response
 */
public function callAction($method, $parameters)
{
    return call_user_func_array([$this, $method], $parameters);
}

总算找到问题所在了,接下来便是解决问题。其实解决问题的方式swoole的文档里也写了,使用\Swoole\Coroutine::call_user_func\Swoole\Coroutine::call_user_func_array代替即可。那么我们只需要在App\Http\Controllers\Controller中重写一下callAction方法,代码如下:

public function callAction($method, $parameters)
{
    return \Swoole\Coroutine::call_user_func_array([$this, $method], $parameters);
}

注意如果在__call()这样的魔术方法里面需要使用$obj->$method(...$arguments)这种方式去处理用\Swoole\Coroutine::call_user_func_array还是会出现问题。

Done!

目前只是遇到这个坑,以后遇到再更新。

本作品采用《CC 协议》,转载必须注明作者和本文链接
只要全力以赴就无所谓失败
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 5
JaguarJack

切到swoole 4吧, 这个问题就解决了

5年前 评论
ThinkQ

不错

5年前 评论

@JaguarJack 试了swoole 4如果不修改call_user_func为swoole协程版,将触发报错

Swoole\Coroutine\MySQL::query(): mysql connection#34 is closed. (SQL: select * from users)

我是尝试在swoole 4中使用协程mysql查询

file


经过测试成功了。。。

5年前 评论

这里只能写原生的嘛?

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!