Spring 基于引导的应用程序中的死信路由

Dead Letter routing in Spring Boot based application

我已经阅读了有关该主题的多个答案,我的配置似乎应该可以正常工作,但由于某些原因却不能。

配置如下:

@Bean Queue intakeQueue(String name) { return new Queue(name, true); }

@Bean Exchange dlx(String name) { return new DirectExchange(name); }

@Bean Queue dlq(String name) { return new Queue(name, false, false, true); }

@Bean
Binding dlb(Exchange dlx, Queue dlq, Queue reply) {
    return BindingBuilder.bind(dlq).to(dlx).with(reply.getName()).noargs();
}

@Bean
Queue replyQueue(String name, Exchange dlx) {
    Map<String, Object> args = new HashMap<>();
    args.put("x-dead-letter-exchange", dlx.getName());
    args.put("x-dead-letter-routing-key", name);
    return new Queue(name, true, false, false, args);
}

RabbitMQ UI 显示回复队列具有 DLXDLK 属性。

我发送的消息像

this.rabbit.convertSendAndReceive(intakeQueue, obj, message -> {
    message.getMessageProperties().setPriority(10);
    return message;
});

消息处理程序在收到消息后立即抛出 AmqpRejectAndDontRequeueException。这样做只是为了测试。我从重试建议开始,但由于它没有产生任何结果,我简化了测试用例。

public Object handleMessage(Object obj) throws IOException {
    throw new AmqpRejectAndDontRequeueException("Testing retries!");
}

我现在看到两个问题:

  1. 抛出 ARADRE 后,DLQ 中永远不会显示消息。不过,如果我直接从 handleMessage 发布到 DLQ,它就会执行。
  2. convertSendAndReceive 没有收到任何东西(可能是例外?)并等待直到超时发生,在我的例子中是 5 分钟。它可能是有意为之,但对于 RPC 风格的调用来说,它相当奇怪。

我是否遗漏或配置错误?

从这个意义上说,它不是 RPC;在侦听器中抛出异常不会传播回发送方。

您拒绝在 intakeQueue 上投递,邮件将被路由到 its DLX/DLQ(如果已配置)。

对于您的测试用例,您应该查看 that DLQ(如果有的话),而不是回复队列的 DLQ。

RabbitMQ 不知道队列关系。您没有显示容器或 RabbitTemplate 配置,但默认情况下使用直接 replyTo 路由(使用 "special" 内部队列)。

您可以配置 rabbit 模板使用固定的回复队列,但是您必须提供一个回复侦听器容器as described in the documentation

如果发件人在收到回复时超时,模板会抛出一个 ARADRE,因此在这种情况下回复将是死信。

为了测试这一点,请让您的侦听器休眠超过超时时间,然后回复;然后您应该会看到回复转到回复队列的 DLQ。

如果您想将异常传播给调用者,您需要return它作为handleMessage return值。

目前没有重新抛出此类异常的逻辑,但是,您必须在代码中这样做(检测到回复是异常并重新抛出)。

当然,异常类型必须是Serializable

您也可以使用 Spring Remoting over AMQP 处理传播异常。