php fpm swoole 异步,基于 Swoole 在 Laravel 中实现异步事件监听及处理

基于 Swoole 在 Laravel 中实现异步事件监听及处理

由 学院君 创建于1年前, 最后更新于 1年前

版本号 #1

9126 views

6 likes

2 collects

这一篇教程我们直接以 hhxsv5/laravel-s 扩展包为例,演示如何在 Laravel 项目中基于 Swoole 实现事件监听。

系统自带事件

首先我们来看一些扩展包自带的系统事件,这些系统事件又可以进一步划分为 Laravel 应用级别的系统事件以及 Swoole 底层 Worker 进程级别的系统事件。

注:在基于 Swoole HTTP 服务器的系统中,Worker 进程相当于 Nginx + PHP-FPM 组合中的 PHP-FPM,关于 Swoole 的底层实现细节后面我们会详细介绍。

应用级别系统事件

首先我们来看扩展包自带的 Laravel 应用请求生命周期中的两个系统事件,分别是 laravels.received_request 和 laravels.generated_response,我们可以通过监听这两个事件来重置或销毁一些全局(global)或静态(static)变量,或者修改当前的请求或响应对象。

laravels.received_request

laravels.received_request 事件会在 LaravelS 扩展包将 Swoole\Http\Request 请求实例转化为 Illuminate\Http\Request 时触发(源码位于 vendor/hhxsv5/laravel-s/src/LaravelS.php):

public function onRequest(SwooleRequest $swooleRequest, SwooleResponse $swooleResponse)

{

try {

parent::onRequest($swooleRequest, $swooleResponse);

$laravelRequest = $this->convertRequest($this->laravel, $swooleRequest);

$this->laravel->bindRequest($laravelRequest);

$this->laravel->fireEvent('laravels.received_request', [$laravelRequest]);

...

由于请求已经转化为 Laravel 请求实例,也将相应的实例信息绑定到 Laravel 容器,并且该事件是通过 Laravel 框架内置的事件分发机制触发的,所以我们可以基于 Laravel 的事件监听机制监听该事件并进行处理,比如,在 app/Providers/EventServiceProvider.php 服务提供者的 boot 方法中添加如下事件监听处理代码:

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Event;

Event::listen('laravels.received_request', function (Request $request, $app) {

$request->query->set('get_key', 'swoole-get-param');// 修改 GET 请求参数

$request->request->set('post_key', 'swoole-post-param'); // 修改 POST 请求参数

});

这个时候我们重新加载一下 Swoole HTTP 服务器,就可以从请求实例中获取到 get_key 和 post_key 参数的值了。

laravels.generated_response

laravels.generated_response 事件会在 Laravel Kernel 处理完请求,扩展包将 Illuminate\Http\Response 响应实例转化为 Swoole\Http\Response 前触发(源码位于 vendor/hhxsv5/laravel-s/src/LaravelS.php,感兴趣的同学自己看下,在处理静态资源和动态资源时都会触发),因此仍然在 Laravel 请求生命周期之内,由于该事件也是通过 Laravel 内置的事件分发机制触发的,所以可以按照 Laravel 监听事件的方式对其进行处理,还是在 app/Providers/EventServiceProvider.php 服务提供者的 boot 方法最后添加如下事件监听处理代码如下:

use Illuminate\Http\Response;

Event::listen('laravels.generated_response', function (Request $request, Response $response, $app) {

$response->headers->set('header-key', 'swoole-header');

});

重新加载 Swoole HTTP 服务器,通过域名 todo-s.test 请求任意路由,就可以看到响应头中包含 header-key 字段了:

1da30bf0924d597e7203f4a8dc7bb16f.png

进程级别系统事件

此外扩展包还提供了几个 Worker 进程级别的系统事件:

事件名

事件监听器接口

触发时间WorkerStart

Hhxsv5\LaravelS\Swoole\Events\WorkerStartInterface

当 Worker/Task 进程启动时触发,此时 Laravel 初始化已经完成

WorkerStop

Hhxsv5\LaravelS\Swoole\Events\WorkerStopInterface

当 Worker/Task 进程正常退出时触发

WorkerError

Hhxsv5\LaravelS\Swoole\Events\WorkerErrorInterface

当 Worker/Task 进程出现异常或错误时触发

由于这几个事件不是通过 Laravel 框架内置的事件分发机制触发,所以需要通过额外的监听机制来实现事件的监听和处理,在 LaravelS 扩展包支持的体系中,我们需要创建实现该事件对应事件监听器接口的事件监听器类,以 WorkerStart 事件为例,对应要实现的接口是 Hhxsv5\LaravelS\Swoole\Events\WorkerStartInterface,我们在 app/Events 目录下创建实现该接口的对应事件监听器类 WorkerStartEventListener,并编写事件处理代码如下:

namespace App\Listeners;

use Hhxsv5\LaravelS\Swoole\Events\WorkerStartInterface;

use Illuminate\Support\Facades\Log;

use Swoole\Http\Server;

class WorkerStartEventListener implements WorkerStartInterface

{

public function __construct()

{

}

public function handle(Server $server, $workerId)

{

Log::info('Worker/Task Process Started');

}

}

然后在配置文件 config/laravels.php 的 event_handlers 配置项中添加事件与事件监听器的映射关系:

'event_handlers' => [

'WorkerStart' => \App\Listeners\WorkerStartEventListener::class,

],

重新启动 Swoole HTTP 服务器,就可以在 storage/logs 目录下最新的 Laravel 日志中看到 Worker/Task Process Started 日志。

自定义异步事件监听及处理

除了扩展包自带的系统事件外,还可以编写自定义的异步事件,该特性基于 Swoole 的异步任务,首先需要在配置文件 config/laravels.php 中设置 swoole.task_worker_num(我们在上一篇教程中已经设置过)。

要实现异步事件监听,需要创建一个继承自 Hhxsv5\LaravelS\Swoole\Task\Event 基类的事件类,我们在 app/Events 目录下创建这个类,类名为 TestEvent,初始化该事件类的代码如下:

namespace App\Events;

use Hhxsv5\LaravelS\Swoole\Task\Event;

class TestEvent extends Event

{

private $data;

public function __construct($data)

{

$this->data = $data;

}

public function getData()

{

return $this->data;

}

}

然后在 app/Listeners 目录下创建一个监听该事件的监听器类 TestEventListener,该监听器继承自 Hhxsv5\LaravelS\Swoole\Task\Listener 基类,初始化监听器代码如下:

namespace App\Listeners;

use App\Events\TestEvent;

use Hhxsv5\LaravelS\Swoole\Task\Event;

use Hhxsv5\LaravelS\Swoole\Task\Listener;

use Illuminate\Support\Facades\Log;

class TestEventListener extends Listener

{

public function __construct()

{

}

public function handle(Event $event)

{

Log::info(__CLASS__ . ': 开始处理', [$event->getData()]);

sleep(3);// 模拟耗时代码的执行

Log::info(__CLASS__ . ': 处理完毕');

}

}

接下来,我们需要在配置文件 config/laravels.php 的 events 配置项中配置自定义事件与事件监听器的映射关系(一个事件可以绑定多个监听器):

'events' => [

\App\Events\TestEvent::class => [

\App\Listeners\TestEventListener::class,

]

],

最后,我们在 routes/web.php 中编写一段测试代码来测试事件的触发:

Route::get('/event/test', function () {

$event = new \App\Events\TestEvent('测试异步事件监听及处理');

$success = \Hhxsv5\LaravelS\Swoole\Task\Event::fire($event);

var_dump($success);

});

重新启动 Swoole HTTP 服务器,在浏览器中访问 http://todo-s.test/event/test,页面会立即返回,对应的事件处理则会异步执行,你可以在 storage/logs 目录下最新的 Laravel 日志中看到相应的事件处理日志。

以上就是 Laravel 中基于 Swoole 实现异步事件监听及处理的简单示例,相较于原生 Laravel 自带的那套推送任务/事件到队列再通过 PHP CLI 启动新进程异步消费队列任务的逻辑,Swoole 原生支持异步任务,极大简化了异步任务和异步事件监听和处理的实现流程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值