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

时间:2015-11-22 06:00:18

标签: spring-amqp spring-rabbit dead-letter spring-rabbitmq

我已经阅读了关于该主题的多个答案,似乎我的配置应该正常工作但由于某种原因它没有。

这是配置:

@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风格的调用来说,这很奇怪。
  3. 我错过了什么或错误配置了什么?

1 个答案:

答案 0 :(得分:1)

从那个意义上来说,它不是RPC;在侦听器中抛出异常将不会传播回发件人。

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

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

RabbitMQ不了解队列关系。您不显示容器或RabbitTemplate配置,但默认情况下,使用直接replyTo路由(使用“特殊”内部队列)。

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

如果发件人在收到回复时超时,则模板会抛出ARADRE,因此在这种情况下回复将会被删除。

为了测试它,在你的监听器中睡眠时间超过超时,然后回复;然后,您应该看到回复转到回复队列的DLQ。

如果要将异常传播给调用者,则需要将其作为handleMessage返回值返回。

目前没有重新抛出此类异常的逻辑,但是,您必须在代码中执行此操作(检测到答复是异常并重新抛出它)。

当然,异常类型必须是Serializable

您还可以使用{{3>} 处理传播异常。