【发布时间】:2023-01-12 00:11:57
【问题描述】:
我想创建一个空名称的队列,以便 RabbitMQ 可以生成该名称 -
var queue = QueueBuilder
.durable("")
.exclusive()
.autoDelete().build
var binding = BindingBuilder.bind(queue).to(exchange).with(bindingKey).noargs();
Declarables d = new Declarables(queue, binding);
但随后调用 getActualName 返回:spring.gen-vuiRwjOmRkihAE8C72rbmw_awaiting_declaration
d.getDeclarablesByType(Queue.class).get(0).getActualName();
而在 rabbitMQ 中,名称是:amq.gen-wpaYnybu9vOdD5v2ej66IQ
在 spring-amqp 核心中,队列构造函数声明:
public Queue(String name, boolean durable, boolean exclusive, boolean autoDelete,
@Nullable Map<String, Object> arguments) {
super(arguments);
Assert.notNull(name, "'name' cannot be null");
this.name = name;
this.actualName = StringUtils.hasText(name) ? name
: (Base64UrlNamingStrategy.DEFAULT.generateName()
+ "_awaiting_declaration");
this.durable = durable;
this.exclusive = exclusive;
this.autoDelete = autoDelete;
}
为什么 spring Queue 使用 Base64UrlNamingStrategy 并在我们需要 rabbitMQ 名称时添加“awaiting_declaration”?我们如何获得 rabbitMQ 名称而不是 spring 生成的名称?
这个用例的原因是因为队列上的竞争条件: “当自动删除或独占队列使用众所周知的(静态)名称时,在客户端断开连接和立即重新连接的情况下,RabbitMQ 节点之间将出现自然竞争条件,将删除此类队列并恢复将尝试重新声明的客户端他们。这可能导致客户端连接恢复失败或异常,并造成不必要的混乱或影响应用程序可用性。”
https://www.rabbitmq.com/queues.html#properties
Spring 建议使用可能导致竞争条件的基于代理的队列: https://docs.spring.io/spring-amqp/docs/current/reference/html/#containers-and-broker-named-queues
编辑: 我们不是自己启动连接,而是管理 bean 在 d.setAdminsThatShouldDelcare(admin) 之后启动它
public Declarables someEventsDeclarables(
@Qualifier("rabbitAdmin") RabbitAdmin admin,
@Qualifier("AmqpExchange") Exchange exchange
) {
final var bindingKey = somePrefix +".*." +someSuffix
final var cfg = new OurEventsDeclarables(
exchange,
"", // no queue name - RabbitMq generates it
bindingKey,
true
);
final var declarables = cfg.declarables();
for (Declarable d : declarables.getDeclarables()) {
d.setAdminsThatShouldDeclare(admin);
admin.declareQueue();
}
return declarables;
}
运行使用队列结果的集成测试
org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$DeclarationException: Failed to declare queue(s):[spring.gen-QUh8ffN0TimELGG_kF1wFw_awaiting_declaration]
【问题讨论】:
-
你如何声明队列?通过
RabbitAdmin声明时,实际名称由DeclareOk结果填充:queue.setActualName(declareOk.getQueue());。 -
我使用调用 d.setAdminsThatShouldDeclare(admin) 的代码中的代码 sn-p 编辑问题;这应该使管理 bean 启动连接。
-
您使用了错误的方法 - 请参阅我的回答。
标签: spring spring-boot rabbitmq spring-amqp