基于 Swoole 构建高性能 Laravel 应用系列 —— 基于 Swoole 在 Laravel 中实现异步事件监听及处理

栏目: PHP · 发布时间: 6年前

内容简介:这一篇教程我们直接以首先我们来看一些扩展包自带的系统事件,这些系统事件又可以进一步划分为 Laravel 应用级别的系统事件以及 Swoole 底层 Worker 进程级别的系统事件。注:在基于 Swoole HTTP 服务器的系统中,Worker 进程相当于 Nginx + PHP-FPM 组合中的 PHP-FPM,关于 Swoole 的底层实现细节后面我们会详细介绍。

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

系统自带事件

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

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

应用级别系统事件

首先我们来看扩展包自带的 Laravel 应用请求生命周期中的两个系统事件,分别是 laravels.received_requestlaravels.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_keypost_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 字段了:

基于 Swoole 构建高性能 Laravel 应用系列 —— 基于 Swoole 在 Laravel 中实现异步事件监听及处理

进程级别系统事件

此外扩展包还提供了几个 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 ,并编写事件处理代码如下:

<?php
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.phpevent_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 ,初始化该事件类的代码如下:

<?php

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 基类,初始化监听器代码如下:

<?php

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.phpevents 配置项中配置自定义事件与事件监听器的映射关系(一个事件可以绑定多个监听器):

'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 原生支持异步任务,极大简化了异步任务和异步事件监听和处理的实现流程。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Cult of the Amateur

The Cult of the Amateur

Andrew Keen / Crown Business / 2007-6-5 / USD 22.95

Amateur hour has arrived, and the audience is running the show In a hard-hitting and provocative polemic, Silicon Valley insider and pundit Andrew Keen exposes the grave consequences of today’s......一起来看看 《The Cult of the Amateur》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

SHA 加密
SHA 加密

SHA 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具