Hyperf-事件机制+异常处理
Hyperf-事件机制+异常处理
标签(空格分隔): php, hyperf
异常处理器
在 Hyperf 里,业务代码都运行在 Worker 进程 上,也就意味着一旦任意一个请求的业务存在没有捕获处理的异常的话,都会导致对应的 Worker 进程 被中断退出,这对服务而言也是不能接受的,捕获异常并输出合理的报错内容给客户端也是更加友好的。
我们可以通过对各个 server 定义不同的 异常处理器(ExceptionHandler),一旦业务流程存在没有捕获的异常,都会被传递到已注册的 异常处理器(ExceptionHandler) 去处理。
异常记录到日志
// 日志类
<?php
declare(strict_types=1);
namespace App\Utils;
class NativeLog
{
private $dirPath;
public function __construct()
{
$this->dirPath = BASE_PATH . '/runtime/logs/' . date("Ymd") . '/';
if (!is_dir($this->dirPath)) {
mkdir($this->dirPath, 0777, true);
}
}
public function error(string $data) : bool
{
$data = "[ ERROR ] [" . date("Y-m-d H:i:s") . "] " . $data . PHP_EOL;
file_put_contents($this->dirPath . "error.log", $data, FILE_APPEND);
return true;
}
}
hyperf 本身就实现了异常类的接管,如果有异常会打印到控制台输出。

// 增加异常信息的记录日志
/**
* 记录文本异常日志
* @param Throwable $throwable
*/
public function writeLog(Throwable $throwable)
{
$AppExceptionLog['server'] = "http";
$AppExceptionLog['method'] = $this->request->getMethod();
$AppExceptionLog['path'] = $this->request->url();
$AppExceptionLog['params'] = $this->request->all();
$AppExceptionLog['file'] = $throwable->getFile();
$AppExceptionLog['line'] = $throwable->getLine();
$AppExceptionLog['message'] = $throwable->getMessage();
(new NativeLog())->error(json_encode($AppExceptionLog));
}
日志记录效果

但是有个问题,try catch 捕获的代码如果有异常就不会记录
引入事件机制
事件模式是一种经过了充分测试的可靠机制,是一种非常适用于解耦的机制,分别存在以下 3 种角色:
事件(Event) 是传递于应用代码与 监听器(Listener) 之间的通讯对象
监听器(Listener) 是用于监听 事件(Event) 的发生的监听对象
事件调度器(EventDispatcher) 是用于触发 事件(Event) 和管理 监听器(Listener) 与 事件(Event) 之间的关系的管理者对象
用通俗易懂的例子来说明就是,假设我们存在一个 UserService::register() 方法用于注册一个账号,在账号注册成功后我们可以通过事件调度器触发 UserRegistered 事件,由监听器监听该事件的发生,在触发时进行某些操作,比如发送用户注册成功短信,在业务发展的同时我们可能会希望在用户注册成功之后做更多的事情,比如发送用户注册成功的邮件等待,此时我们就可以通过再增加一个监听器监听 UserRegistered 事件即可,无需在 UserService::register() 方法内部增加与之无关的代码。
代码示例
// 新增异常事件
<?php
declare(strict_types=1);
namespace App\Event;
/**
* 系统异常事件
* Class AppException
* @package App\Event
*/
class AppException
{
public $throwable;
public function __construct($throwable)
{
$this->throwable = $throwable;
}
}
// 新增异常事件监听器
<?php
declare(strict_types=1);
namespace App\Listener;
use App\Event\AppException;
use App\Utils\NativeLog;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\HttpServer\Contract\RequestInterface;
/**
* 异常事件监听器
* Class AppExceptionListener
* @package App\Listener
* @Listener()
*/
class AppExceptionListener implements ListenerInterface
{
/**
* @Inject()
* @var RequestInterface
*/
private $request;
/**
* @Inject()
* @var NativeLog
*/
private $nativeLog;
/**
* @inheritDoc
*/
public function listen(): array
{
// TODO: Implement listen() method.
// 返回一个该监听器要监听的事件数组,可以同时监听多个事件
return [
AppException::class,
];
}
/**
* @param object $throwable
*/
public function process(object $throwable)
{
$throwable = $throwable->throwable;
$request = $this->request;
$AppExceptionLog['server'] = "http";
$AppExceptionLog['method'] = $request->getMethod();
$AppExceptionLog['path'] = $request->url();
$AppExceptionLog['params'] = $request->all();
$AppExceptionLog['file'] = $throwable->getFile();
$AppExceptionLog['line'] = $throwable->getLine();
$AppExceptionLog['message'] = $throwable->getMessage();
$this->nativeLog->error(json_encode($AppExceptionLog));
}
}
// 控制器
<?php
declare(strict_types=1);
namespace App\Admin\Controller;
use App\Admin\Model\UserModel;
use App\Admin\Service\UserService;
use App\Event\AppException;
use App\Rpc\Inter\UserServiceInter;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\Utils\Context;
use Psr\EventDispatcher\EventDispatcherInterface;
use function _HumbugBoxa5be08ba8ddb\React\Promise\Stream\first;
/**
* 用户控制器
* Class UserController
* @package App\Admin\Controller
* @AutoController()
*/
class UserController extends AdminBaseController
{
/**
* @Inject
* @var EventDispatcherInterface
*/
private $eventDispatcher;
/**
* 异常测试
*/
public function exception()
{
try {
array_column();
} catch (\Throwable $throwable) {
$this->eventDispatcher->dispatch(new AppException($throwable));
}
}
Hyperf-事件机制+异常处理的更多相关文章
- 【移动端兼容问题研究】javascript事件机制详解(涉及移动兼容)
前言 这篇博客有点长,如果你是高手请您读一读,能对其中的一些误点提出来,以免我误人子弟,并且帮助我提高 如果你是javascript菜鸟,建议您好好读一读,真的理解下来会有不一样的收获 在下才疏学浅, ...
- tkinter事件机制
一.tkinter.Event tkinter的事件机制跟js是一样的,也是只有一个Event类,这个类包罗万象,集成了键盘事件,鼠标事件,包含各种参数. 不像java swing那种强类型事件,sw ...
- [解惑]JavaScript事件机制
群里童鞋问到关于事件传播的一个问题:“事件捕获的时候,阻止冒泡,事件到达目标之后,还会冒泡吗?”. 初学 JS 的童鞋经常会有诸多疑问,我在很多 QQ 群也混了好几年了,耳濡目染也也收获了不少,以后会 ...
- Atitit 数据库的事件机制--触发器与定时任务attilax总结
Atitit 数据库的事件机制--触发器与定时任务attilax总结 1.1. 事件机制的图谱1 2. 触发器的类型2 3. 实现原理 After触发器 Vs Instead Of触发器2 3.1. ...
- 深入浅出iOS事件机制
原文地址: http://zhoon.github.io/ios/2015/04/12/ios-event.html 本文章将讲解有关iOS事件的传递机制,如有错误或者不同的见解,欢迎留言指出. iO ...
- Java 事件机制
java事件机制包括三个部分:事件.事件监听器.事件源. 1.事件.一般继承自java.util.EventObject类,封装了事件源对象及跟事件相关的信息,用于listener的相应的方法之中,作 ...
- Angular $scope和$rootScope事件机制之$emit、$broadcast和$on
Angular按照发布/订阅模式设计了其事件系统,使用时需要“发布”事件,并在适当的位置“订阅”或“退订”事件,就像邮箱里面大量的订阅邮件一样,当我们不需要时就可以将其退订了.具体到开发中,对应着$s ...
- JavaScript 详说事件机制之冒泡、捕获、传播、委托
DOM事件流(event flow )存在三个阶段:事件捕获阶段.处于目标阶段.事件冒泡阶段. 事件捕获(event capturing):通俗的理解就是,当鼠标点击或者触发dom事件时,浏览器会 ...
- DOM事件机制进一步理解
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...
随机推荐
- kafka 通俗
把broker比作是一幢摩天大楼,一个10节点的kafka集群就是10幢摩天大楼,而且这些大楼都长得一模一样.分区就相当于大楼里的一层.一个分区就相当于一整层哦.原先大楼是空的.现在用户创建了一个to ...
- 2288.【POJ Challenge】生日礼物 链表+堆+贪心
BZOJ2288 [POJ Challenge]生日礼物 题意: 给一个长度为\(n\)的数组,最多可以选\(m\)个连续段,问选取的最大值是多少 题解: 先把连续的符号相同的值合并,头和尾的负数去掉 ...
- Educational Codeforces Round 89 (Rated for Div. 2) C. Palindromic Paths(贪心)
题目链接:https://codeforces.com/contest/1366/problem/C 题意 有一个 $n \times m$ 的 $01$迷宫,要使从 $(1,1)$ 到 $(n,m) ...
- Codeforces Round #648 (Div. 2) D. Solve The Maze
这题犯了一个很严重的错误,bfs 应该在入队操作的同时标记访问,而不是每次只标记取出的队首元素. 题目链接:https://codeforces.com/contest/1365/problem/D ...
- 【hdu 3579】Hello Kiki(数论--拓展欧几里德 求解同余方程组)
题意:Kiki 有 X 个硬币,已知 N 组这样的信息:X%x=Ai , X/x=Mi (x未知).问满足这些条件的最小的硬币数,也就是最小的正整数 X. 解法:转化一下题意就是 拓展欧几里德求解同余 ...
- codeforces622E Ants in Leaves (dfs)
Description Tree is a connected graph without cycles. A leaf of a tree is any vertex connected with ...
- Network of Schools POJ - 1236 有向强连通图
//题意://给你n个学校,其中每一个学校都和一些其他学校有交流,但是这些边都是单向的.你至少需要给几个学校//传递消息可以使全部学校都收到消息,第二问你最少添加几条边可以使它变成一个强连通图//题解 ...
- 01背包记录路径 (例题 L3-001 凑零钱 (30分))
题意: 就是找出来一个字典序最小的硬币集合,且这个硬币集合里面所有硬币的值的和等于题目中的M 题解: 01背包加一下记录路径,如果1硬币不止一个,那我们也不采用多重背包的方式,把每一个1硬币当成一个独 ...
- Redis 多实例 & 主从复制
Redis 多实例 多实例目录 [root@db01 ~]# mkdir /service/redis/{6380,6381} 多实例配置文件 # 第一台多实例配置 [root@db01 ~]# vi ...
- 手工数据结构系列-C语言模拟栈 hdu1022
这个题我一开始是这么想的.. 爆搜所有可能的出栈序列 然后对输入进行匹配 这样我感觉太慢 然后我们可以想到直接通过入栈序列对出栈序列进行匹配 但是我犯了一个错误..那就是出栈序列一定到入栈序列里找.. ...