Java RabbitMQ-Apache骆驼读取消息如何处理失败的消息

Java RabbitMQ-Apache骆驼读取消息如何处理失败的消息,java,rabbitmq,dead-letter,Java,Rabbitmq,Dead Letter,我有以下PHP应用程序。将用户注册发布到消息队列的。Java应用程序从该队列中读取并导入它。希望下面的图表能说明这一点。我只从事Java方面的工作。队列上已存在json消息 路由(Java消费端)。 @Component public class SignUpRouting { errorHandler(deadLetterChannel("rabbitmq://signUpDeadLetter.exchange?username=etc..").useOriginalMessage()

我有以下PHP应用程序。将用户注册发布到消息队列的。Java应用程序从该队列中读取并导入它。希望下面的图表能说明这一点。我只从事Java方面的工作。队列上已存在json消息

路由(Java消费端)。

@Component
public class SignUpRouting {

  errorHandler(deadLetterChannel("rabbitmq://signUpDeadLetter.exchange?username=etc..").useOriginalMessage());

  from("rabbitmq://phpSignUp.exchange?username=etc....")
            .routeId("signUpRoute")
            .processRef("signUpProcessor")
            .end();
  //.... 
处理器..

@Component
public class SignupProcessor implements Processor {

    private ObjectMapper mapper = new ObjectMapper();

    @Override
    public void process(Exchange exchange) throws Exception {

        String json = exchange.getIn().getBody(String.class);
        SignUpDto dto = mapper.readValue(json, SignUpDto.class);

        SignUp signUp = new SignUp();
        signUp.setWhatever(dto.getWhatever());
        //etc....

        // save record
        signUpDao.save(signUp);
    }
}
我的问题是..当处理器无法导入消息时,我该怎么办

比如说,有一个DAO异常。数据字段可能已关闭或导入的格式不正确。我不想失去这个信息。我希望看到错误并重试导入。但是我不想每30秒就重复一次

我想我需要创建另一个队列。。一个死信队列,并让该队列每6小时不确定地重试一次消息?。。然后我会查看日志,查看错误并上传修复,然后重新处理消息

我将如何实现这一点?还是我走错了路

编辑我已尝试设置deadLetterExchange,以查看是否可以使事情朝着正确的方向发展。。。但是,它会出错,并表示队列不能为非空


您可以使用OneException捕获异常,如果出现异常,消息将被路由到死信交换,以下是Spring DSL中的示例:


java.sql.SQLException

以下是使用死信标题的示例:

        <from uri="rabbitmq://localhost/youexchange?queue=yourq1&amp;
            exchangeType=topic&amp;
            routingKey=user.reg.*&amp;
            deadLetterExchange=dead.msgs&amp;
            deadLetterExchangeType=topic&amp;
            deadLetterRoutingKey=dead.letters&amp;
            deadLetterQueue=dead.letters&amp;
            autoAck=false&amp;
            autoDelete=false"/>

          <!--We can use onException to make camel to retry, and after that, dead letter queue are the fallback-->
        <onException useOriginalMessage="true">
            <exception>java.lang.Exception</exception>
            <redeliveryPolicy asyncDelayedRedelivery="true" maximumRedeliveries="3" redeliveryDelay="5000"/>
        </onException>

java.lang.Exception
我们需要关闭自动确认并设置死信队列,然后如果抛出异常,消息将位于死信队列中。
要使用OneException,我们可以在将消息驼峰式丢弃到死信队列之前控制重试。

如果您使用的是另一个队列,为什么不将失败的消息与异常的堆栈跟踪一起存储,然后处理该队列中的数据?我不确定是否理解。你能举个例子吗?如果你有一个豪华的支持团队,我会将消息发送到另一个队列或写入数据库表,然后发送电子邮件通知支持人员。创建另一个界面,允许支持人员修改消息文本并将其重新导入注册处理器。无论你做什么都需要人工干预。据此设计。PHP应用程序上应该有很好的验证,这样his是一个罕见的事件。这是一个很好的答案,也是一个可行的解决方案+1。然而,我觉得它没有使用rabbitmq特定的死信头和配置。如前所述,我们为什么需要将bridgeEndpoint设置为true。这是为什么?如果不添加属性,目标队列将不会收到任何消息。有几个问题。为什么我们需要打开自动确认?什么是deadLetterExchangeType=topic?如果autoAck打开,camel将在接收消息时发送basic.ack。在例外情况下,camel将无法发送basic.reject或basic.nack,因此死信属性将无效。并且死信交换EXXX属性用于将死信路由到指定的交换和队列。在演示设置中,我使用了主题,但您可以使用其他exchange类型。
<onException useOriginalMessage="true">
            <exception>java.sql.SQLException</exception>
            <redeliveryPolicy asyncDelayedRedelivery="true" maximumRedeliveries="1" redeliveryDelay="1000"/>

            <inOnly uri="rabbitmq://localhost/dead.msgs?exchangeType=fanout&amp;
                    autoDelete=false&amp;
                    bridgeEndpoint=true"/>
</onException>
        <from uri="rabbitmq://localhost/youexchange?queue=yourq1&amp;
            exchangeType=topic&amp;
            routingKey=user.reg.*&amp;
            deadLetterExchange=dead.msgs&amp;
            deadLetterExchangeType=topic&amp;
            deadLetterRoutingKey=dead.letters&amp;
            deadLetterQueue=dead.letters&amp;
            autoAck=false&amp;
            autoDelete=false"/>

          <!--We can use onException to make camel to retry, and after that, dead letter queue are the fallback-->
        <onException useOriginalMessage="true">
            <exception>java.lang.Exception</exception>
            <redeliveryPolicy asyncDelayedRedelivery="true" maximumRedeliveries="3" redeliveryDelay="5000"/>
        </onException>