

hyperf Error 处理 和 队列异常重试处理的问题
source link: https://surest.cn/archives/198/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

消息队列配置
config/autoload/async_queue.php
这里可以直接参考 default 拷贝多个队列配置即可
每个新的配置都为一个新的队列,与其他队列互不干扰
注意点: 如果多个项目 并且使用同个队列名称 且同个 redis 库,会造成读取互相的数据,造成意料之外的错误
建议不同的项目使用不同的 DB
列出常用的代码
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\Utils\ApplicationContext;
...
/**
* 获取一个实例
* DateTime: 2021/11/30 9:34 上午
*/
public static function getDriver($driver = 'default')
{
return ApplicationContext::getContainer()->get(DriverFactory::class)->get($driver);
}
----
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\ApplicationContext;
use Psr\Log\LoggerInterface;
/**
* 获取 Logger 实例
* DateTime: 2021/12/3 9:47 上午
* @param string $name
* @return LoggerInterface
*/
public static function get(string $name = 'default'): LoggerInterface
{
return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name, $name);
}
---
use Hyperf\Redis\RedisFactory;
use Hyperf\Utils\ApplicationContext;
/**
* 获取 Logger 实例
* DateTime: 2021/12/3 9:47 上午
* @param string $name
* @return LoggerInterface
*/
public static function get(string $name = 'default'): LoggerInterface
{
return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name, $name);
}
以上为获取常用的几个实例的方式
设置异常接管
# AppExceptionHandler.php
/**
* @var StdoutLoggerInterface
*/
protected $logger;
public function __construct(StdoutLoggerInterface $logger)
{
$this->logger = $logger;
}
public function handle(Throwable $throwable, ResponseInterface $response)
{
$this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
$this->logger->error($throwable->getTraceAsString());
$this->errorToFile($throwable);
return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream('Internal Server Error.'));
}
public function isValid(Throwable $throwable): bool
{
dump("---------------------");
return true;
}
public function errorToFile(Throwable $throwable)
{
$logger = Logger::get("error");
$logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
$logger->error($throwable->getTraceAsString());
ErrorHandle::handle($throwable);
}
这里演示的结果包含 错误投递的处理 及 重试
namespace App\Job;
use App\Container\Logger;
use Hyperf\AsyncQueue\Job;
class TestJob extends Job
{
protected $maxAttempts = 2;
protected $params = [];
public function __construct(array $params)
{
// 这里最好是普通数据,不要使用携带 IO 的对象,比如 PDO 对象
// 即为 不要传递 类似如 new Job() | New User() 这种实例化对象进来,这个地方如 队列的时候 会进行 serialize 序列化,不然后续读取需要解析其命名空间和实例对象 无法进行解析的
$this->params = $params;
}
public function handle()
{
// ... 执行我们的业务逻辑
Logger::get('error')->info('手动触发 Error' . format_now(), $this->params);
throw new \Exception("手动触发 Error");
}
}
测试后发现,我们无法无法在 AppExceptionHandler 监听到我们的异常 【这个其实是正常的,他针对的是 http 的异常接管】
我们需要手动创建事件监听器,这里就不再细说,直接贴代码吧
抛出异常 和 监听 队列异常
想要监听到队列的异常,我们只需要在我们队列的业务逻辑处理中 抛出我们的 error 即可
public function handle()
{
// ... 执行我们的业务逻辑
Logger::get('error')->info('手动触发 Error' . format_now(), $this->params);
// 抛出 error
throw new \Exception("手动触发 Error");
}
# App\Listener
namespace App\Listener;
use App\Container\Logger;
use App\Services\Notify\ErrorHandle;
use Hyperf\AsyncQueue\Event\FailedHandle;
use Hyperf\Crontab\Event\FailToExecute;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
#[Listener]
class QueueCrontabListener implements ListenerInterface
{
public function listen(): array
{
return [
FailedHandle::class,
];
}
/**
* @param FailedHandle $event
*/
public function process(object $event)
{
$throwable = $event->getThrowable();
$message = sprintf("[%s] [Queue Error] [%s]", format_now(), $throwable->getMessage());
ErrorHandle::handle($throwable, [], $message);
}
}
ErrorHandle::handle
为我写的全局 error 处理器
class ErrorHandle
...
public static function handle(\Throwable $throwable, array $params = [], $message = null)
{
$exportHtml = ExceptionReport($throwable);
Logger::get('error')->error("error handle", compact('exportHtml','params', 'message'));
$message && dingtoo('error')->text($message);
if(env('APP_ENV') == 'dev') { return; }
try {
$html = ExceptionReportHtml($exportHtml, $throwable->getTrace());
$html = $html . json_encode($params);
$emails = explode( ',', env('DEVELOP_EMAIL'));
$service = new MailerService();
$emails && array_map(function ($email) use ($service, $html){
$service->smtpMail($email, 'Error', $html);
}, $emails);
}catch (\Throwable $e) {
Logger::get('error')->error("error handle", ExceptionReport($e));
}
}
本文由 邓尘锋 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Dec 31, 2021 at 11:04 am
Recommend
-
23
hyperf-skeleton v1.0.3 Added 安装器为 RPC 部分增加 JSON RPC with Service Governance 选项, 选择该选项会自动安装
-
33
-
15
众所周知 Hyperf 是不支持单独启动某个服务的,所以有类似需求的小伙伴确实比较头疼。 作为 Hyperf 作者,接到过很多这类需求和 PR,但都被我毙了,因为框架提供了极大的自由度,这些东西完全可以自己扩展。 以...
-
9
经常用腾讯云云函数能力的同学肯定遇到过事件重试,目前为止除了两个常见的出口触发器 APIGW/CLB和一个流式kafka同步触发器,大部分触发器其实都是都是异步的。如何保证异步触发器在出现各种报错的情况下合理的被重试和消费是这篇文章探索...
-
7
Hyperf 2.2 版发布!| 企业级的渐进式 PHP 协程框架首先感谢所有 Hyperf 的支持者,从发布至今两年的时间里,我们坚持每周发布一个小版本,截止至今已经发布了超过 106 个版本,这是 Hyper...
-
1
术→技巧, 研发 Python异常重试解决方案 钱魏Way · 2020-10-14 · 9...
-
12
V2EX › PHP Hyperf 3.0 开发中! limingxinleo · 2 天前 · 1085 次点击
-
5
如何使用 Nginx + supervisord 部署 Hyperf 项目 Published on Dec 3, 2021 in PHP with 0 comment ...
-
11
一、延时队列 TimingWheel是kafka时间轮的实现,内部包含了⼀个TimerTaskList数组,每个数组包含了⼀些链表组成的TimerTaskEntry事件,每个TimerTaskList表示时间轮的某⼀格,这⼀格的时间跨度为tickMs,同⼀个TimerTaskList中的事件都是...
-
7
深入 Hyperf:HTTP 服务启动时发生了什么? ...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK