转发自白狼栈:查看原文

在使用 hyperf 官方自带的 AMQP 队列时你会发现,不需要我们再额外启动进程对消息进行消费。这是因为默认情况下,使用 @Consumer 注解时,hyperf 会为我们自动创建子进程启动消费者,并且会在子进程异常退出后,重新拉起。

来看一个简单的例子。

1、创建producer

php bin/hyperf.php gen:amqp-producer DemoProducer

2、投递消息

namespace App\Controller;

use App\Amqp\Producer\DemoProducer;
use Hyperf\Amqp\Producer;
use Hyperf\Utils\ApplicationContext; class IndexController extends AbstractController
{
public function index()
{
$user = $this->request->input('user', 'Hyperf'); $data = [
'message' => "Hello {$user}.",
];
$message = new DemoProducer($data);
$producer = ApplicationContext::getContainer()->get(Producer::class);
$producer->produce($message); return 'ok';
}
}

3、创建消费者

php bin/hyperf.php gen:amqp-consumer DemoConsumer

4、测试

启动项目,浏览器访问 http://127.0.0.1:9501/ ,我们可以在控制台看到打印的消息输出。

Array
(
[method] => GET
[message] => Hello Hyperf.
)
[DEBUG] 1 acked.

这个是 hyperf 自启动进程对消息进行消费。

现在我们想把消费进程从项目中剥离出来,用其他机器单独进行消费。

我们参考 hyperf 自启动的流程+command 实现。

下面先看看 hyperf 源码是怎么实现自启动消费者进程的。

首先我们注意到 Hyperf\Amqp\Listener\BeforeMainServerStartListener 这个监听器,在 BeforeMainServerStart 或者 MainCoroutineServerStart 事件被触发时,Hyperf\Amqp\ConsumerManager::run 方法被执行。

public function process(object $event)
{
// Init the consumer process.
$consumerManager = $this->container->get(ConsumerManager::class);
$consumerManager->run();
}

Hyperf\Amqp\ConsumerManager::run 方法如下:



大致步骤都在图上进行了标注,可以看到整个过程都比较简单。

下面我们参考这个过程,根据 command 来手动创建消费进程。

1、原 consumer 先禁用

【App\Amqp\Consumer\DemoConsumer】enable 设置 false

public function isEnable(): bool
{
return false;
}

2、手动创建一个新的 consumer 用于测试

<?php

declare(strict_types=1);

namespace App\Amqp\Consumer;

use Hyperf\Amqp\Result;
use Hyperf\Amqp\Annotation\Consumer;
use Hyperf\Amqp\Message\ConsumerMessage;
use PhpAmqpLib\Message\AMQPMessage; class DemoConsumer2 extends ConsumerMessage
{
public $exchange = 'hyperf';
public $routingKey = 'hyperf';
public $queue = 'hyperf'; public function consumeMessage($data, AMQPMessage $message): string
{
print_r($data); return Result::ACK;
} public function isEnable(): bool
{
return false;
}
}

在这个 consumer 中,我们手动指定了 exchange、routingKey 和 queue,同时禁止自启动(enable=false)。

3、构建 command

php bin/hyperf.php gen:command DemoConsumerCommand

【App\Command\DemoConsumerCommand】代码如下:
<?php declare(strict_types=1); namespace App\Command; use App\Amqp\Consumer\DemoConsumer;
use App\Amqp\Consumer\DemoConsumer2;
use Hyperf\Amqp\Consumer;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
use Hyperf\Di\Annotation\AnnotationCollector;
use Psr\Container\ContainerInterface;
use Hyperf\Amqp\Annotation\Consumer as ConsumerAnnotation; /**
* @Command
*/
#[Command]
class DemoConsumerCommand extends HyperfCommand
{
/**
* @var ContainerInterface
*/
protected $container; public function __construct(ContainerInterface $container)
{
$this->container = $container; parent::__construct('DemoConsumer:command');
} public function configure()
{
parent::configure();
$this->setDescription('手动启动消费进程测试');
} public function handle()
{
$consumer = $this->container->get(Consumer::class);
$consumer->consume(make(DemoConsumer2::class)); $this->line('ok.', 'info');
}
}

4、重新启动 hyperf 以及另起一个窗口启动 command

启动 hyperf : php bin/hyperf.php start
启动 command: php bin/hyperf.php DemoConsumer:command

5、测试

浏览器访问 http://127.0.0.1:9501/ ,我们可以在启动 command 的窗口看到消息被成功输出。

hyperf 如何对AMQP消息进行手动消费?的更多相关文章

  1. RabbitMQ消息发布和消费的确认机制

    前言 新公司项目使用的消息队列是RabbitMQ,之前其实没有在实际项目上用过RabbitMQ,所以对它的了解都谈不上入门.趁着周末休息的时间也猛补习了一波,写了两个窗体应用,一个消息发布端和消息消费 ...

  2. 消息队列手动确认Ack

    以RabbitMQ为例,默认情况下 RabbitMQ 是自动ACK机制,就意味着 MQ 会在消息发送完毕后,自动帮我们去ACK,然后删除消息的信息.这样依赖就存在这样一个问题:如果消费者处理消息需要较 ...

  3. 高可用保证消息绝对顺序消费的BROKER设计方案

    转自: http://www.infoq.com/cn/articles/high-availability-broker-design?utm_source=tuicool&utm_medi ...

  4. 分布式消息队列RocketMQ&Kafka -- 消息的“顺序消费”

    在说到消息中间件的时候,我们通常都会谈到一个特性:消息的顺序消费问题.这个问题看起来很简单:Producer发送消息1, 2, 3... Consumer按1, 2, 3...顺序消费. 但实际情况却 ...

  5. RocketMQ的消息发送及消费

    RocketMQ消息支持的模式: 消息支持的模式分为三种:NormalProducer(普通同步),消息异步发送,OneWay. 消息同步发送: 普通消息的发送和接收在前面已经演示过了,在前面的案例中 ...

  6. springboot集成websocket实现向前端浏览器发送一个对象,发送消息操作手动触发

    工作中有这样一个需示,我们把项目中用到代码缓存到前端浏览器IndexedDB里面,当系统管理员在后台对代码进行变动操作时我们要更新前端缓存中的代码怎么做开始用想用版本方式来处理,但这样的话每次使用代码 ...

  7. RabbitMQ 入门系列:7、保障消息不重复消费:产生消息的唯一ID。

    系列目录 RabbitMQ 入门系列:1.MQ的应用场景的选择与RabbitMQ安装. RabbitMQ 入门系列:2.基础含义:链接.通道.队列.交换机. RabbitMQ 入门系列:3.基础含义: ...

  8. SpringBoot整合RabbitMQ,实现消息发送和消费以及多个消费者的情况

    下载安装Erlang和RabbitMQ Erlang和RabbitMQ:https://www.cnblogs.com/theRhyme/p/10069611.html AMQP协议 https:// ...

  9. rabbitMQ应用,laravel生产广播消息,springboot消费消息

    最近做一个新需求,用户发布了动态,前台需要查询,为了用户读取信息响应速度更快(MySQL很难实现或者说实现起来很慢),所以在用户动态发布成功后,利用消息机制异步构建 redis缓存 和 elastic ...

随机推荐

  1. 网络安全:关于SecOC及测试开发实践简介

    前言 我们知道,在车载网络中,大部分的数据都是以明文方式广播发送且无认证接收.这种方案在以前有着低成本.高性能的优势,但是随着当下智能网联化的进程,这种方案所带来的安全问题越来越被大家所重视. 为了提 ...

  2. ASP.NET VS 调试提示:指定的端口正在使用中,建议切换到xxx之外并大于1024的端口

    问题描述 使用 Visual Studio 开发 ASP.NET 网站的过程中,突然提示端口被占用: 解决方式 在启动项目上右键→属性,切换到 Web .直接修改服务器栏目里面的端口号,解决!

  3. Kubernetes 集群无损升级实践 转至元数据结尾

    一.背景 活跃的社区和广大的用户群,使 Kubernetes 仍然保持3个月一个版本的高频发布节奏.高频的版本发布带来了更多的新功能落地和 bug 及时修复,但是线上环境业务长期运行,任何变更出错都可 ...

  4. 论文翻译:2021_MetricGAN+: An Improved Version of MetricGAN for Speech Enhancement

    论文地址:MetricGAN+:用于语音增强的 MetricGAN 的改进版本 论文代码:https://github.com/JasonSWFu/MetricGAN 引用格式:Fu S W, Yu ...

  5. LuoguP6553 Strings of Monody 题解

    Content 给定一个长度为 \(n\) 的字符串 \(s\)(仅包含 \(1,4,5\) 三种字符,\(n\) 在本题中无需输入),有 \(m\) 个操作,每次操作给定两个整数 \(l,r\),再 ...

  6. Python sys模块 os模块、OS.open() | open() | OS._exit() | sys.exit() | exit()

    sys模块:负责程序和Python交互. sys常用方法:===========================  sys.stdout.write('please:')val = sys.stdin ...

  7. pdf2swf转换不成功该怎么解决啊,Process p=r.exec("D:/swf/pdf2swf.exe \""+pdfFile.getPath()+"\" -o \""+swfFile.getPath()+"\" -T 9");

    pdf2swf转换不成功该怎么解决啊,可以这样解决吧,请注意命令的用法啊:Process p=r.exec("D:/swf/pdf2swf.exe  \""+pdfFil ...

  8. AcWing1264. 动态求连续区间和 (树状数组做法)

    1.题目 给定 n 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列 [a,b] 的连续和. 输入格式 第一行包含两个整数 n 和 m,分别表示数的个数和操作次数. 第二行包含 n ...

  9. SpringCloud使用GateWay网关前端请求请求跨域处理

    增加配置类 CorsConfig.java import org.springframework.context.annotation.Bean; import org.springframework ...

  10. c++之可变参数格式化字符串(c++11可变模板参数)

    本文将使用 泛型 实现可变参数. 涉及到的关见函数:  std::snprintf 1.一个例子 函数声明及定义 1 // 泛型 2 template <typename... Args> ...