【问题标题】:Spring boot JMS : How not to lose jms message when internal application error happens at the JMS receiverSpring boot JMS:当JMS接收器发生内部应用程序错误时如何不丢失jms消息
【发布时间】:2020-09-08 09:05:04
【问题描述】:

如果JMS接收器由于数据库连接失败等原因失败,则JMS消息将丢失。任何人都可以建议我避免使用 Spring Boot 应用程序丢失 JMS 消息的常见解决方案是什么

如果在接收端处理消息时出现错误,我是否应该将消息重新发送回它起源的队列?

这是我的场景源代码。

@SpringBootApplication
public class MainApp {

    public static void main(String[] args) {
        SpringApplication.run(MainApp.class, args);
    }

    @Bean
    public JmsListenerContainerFactory<?> sdbFactory(ConnectionFactory connectionFactory,
                                                    DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        // This provides all boot's default to this factory, including the message converter
        configurer.configure(factory, connectionFactory);
        // You could still override some of Boot's default if necessary.
        return factory;
    }

    @Bean
    public Queue queue() {
        return new ActiveMQQueue("sdb.orderQueue");
    }



    @Bean
    public MessageConverter jacksonJmsMessageConverter() {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setTargetType(MessageType.TEXT);
        converter.setTypeIdPropertyName("_type");
        return converter;
    }

    @Bean
    public ModelMapper mapper() {
        ModelMapper mapper = new ModelMapper();
        mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
        return mapper;
    }

}

制片人

@RestController
@RequestMapping("/transaction")
public class OrderTransactionController {

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    private static final Logger LOGGER =
            LoggerFactory.getLogger(OrderTransactionController.class);

    @PostMapping("/send")
    public void send(@RequestBody OrderDTO order)  {
        LOGGER.info("Sending a transaction."+ order);
        jmsMessagingTemplate.convertAndSend("sdb.orderQueue", order);
    }
}

消费者

@Component
public class OrderMessageReceiver {

    @Autowired
    OrderService service;

    @Autowired
    ModelMapper modelMapper;

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    private static final Logger LOGGER =
            LoggerFactory.getLogger(OrderMessageReceiver.class);

    @JmsListener(destination = "sdb.orderQueue", containerFactory = "sdbFactory")
    public void receiveQueue(OrderDTO order) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        ModelMapper modelMapper = new ModelMapper();

        OrderEntity orderEntity = modelMapper.map(order, OrderEntity.class);
        try {
            service.createOrder(orderEntity);
        } catch (Exception e) {
            LOGGER.error("Error happend while trying to persist order : {} error is : {}",order, e);


        }
    }


}

【问题讨论】:

  • 在处理完成之前不要确认消息,这样如果处理失败,消息仍会在队列中,稍后可以传递给另一个消费者。
  • 我是否可以控制确认,如果可以,我该如何在 Spring Boot 中进行操作以避免在处理成功完成之前确认发件人

标签: spring-boot jms message-queue spring-jms


【解决方案1】:

您需要展示您如何使用它以及配置,但默认情况下,使用DefaultMessageListenerContainer 会话将为transacted,因此如果侦听器向容器抛出异常,事务将回滚并且消息添加回队列。

如果监听器正常退出,事务会提交,消息会被移除。

【讨论】:

  • 我已经用监听生产者的配置更新了问题
  • 因为您正在捕获异常,这就是侦听器认为事务已提交的原因。请在记录错误后尝试抛出异常。
  • DefaultMessageListenerContainer默认不事务,代码sn-ps不使用事务。但是,其他海报是正确的,通过在 receiveQueue 方法中捕获异常并返回,消息将被确认。您可能希望实现一个简单的 errorHandler,如下所示:memorynotfound.com/… 如果调用了任何错误处理程序,则不会确认消息。或者,您可以抛出异常并希望许多默认错误处理程序之一可以处理它。
  • @DougGrove 由于 OP 使用 Spring Boot 的自动配置容器工厂,它创建的容器确实是默认事务处理的 - 请参阅 here
猜你喜欢
  • 1970-01-01
  • 2019-07-29
  • 2020-11-16
  • 1970-01-01
  • 1970-01-01
  • 2017-01-28
  • 1970-01-01
  • 2011-12-12
  • 1970-01-01
相关资源
最近更新 更多