StringBoot集成Rabbit,根據業務返回ACK

為了維護消息的有效性,當消費消息時候處理失敗時候,不進行消費,需要我們根據業務區返回ACK,本項目我使用Redis和ack機制雙重保險,保障消息一定能夠正確的消費
  • 首先,接著上部分內容,使用Topic,機制(不明白的,可以回顧上部分內容)

  • 上部分內容,我們使用SpringBoot注解,去實現,但是控制權不完全賬務,當進行大規模項目時候,不太建議使用


 @RabbitListener(queues = TopicRabbitConfig.USER_QUEUE)
    @RabbitHandler
    public void processUser(String message) {
        threadPool.execute(new Runnable() {
            @Override
            public void run() {
                logger.info("用戶側流水:{}",message);
            }
        });
    }
  • 根據源碼分析,當然這里不分析源碼,有興趣的可以多失敗幾次就ok明白了

  • 在配置類中定義監聽器,監聽這個序列(AcknowledgeMode.MANUAL是必須的哦)


    /**
     * 接受消息的監聽,這個監聽客戶交易流水的消息
     * 針對消費者配置
     * @return
     */
    @Bean
    public SimpleMessageListenerContainer messageContainer1(ConnectionFactory connectionFactory, TransactionConsumeImpl transactionConsume) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
        container.setQueues(queueMessage());
        container.setExposeListenerChannel(true);
        container.setMaxConcurrentConsumers(1);
        container.setConcurrentConsumers(1);
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL); //設置確認模式手工確認
        container.setMessageListener(transactionConsume);
        return container;
    }

這個 TransactionConsumeImpl 要繼承ChannelAwareMessageListener,主要說的手動返回ACK就是channel。調用


@Component
public class TransactionConsumeImpl implements ChannelAwareMessageListener {
    private static final Logger logger = LoggerFactory.getLogger(TransactionConsumeImpl.class);
    private static final Gson gson = new Gson();

    @Autowired
    JedisShardInfo jedisShardInfo;
    @Autowired
    ExecutorService threadPool;
    @Autowired
    BoluomeFlowService boluomeFlowService;

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        String boby = new String(message.getBody(), "utf-8");//轉換消息,我們是使用json數據格式
        threadPool.execute(new Runnable() {   //多線程處理
            @Override
            public void run() {
                Jedis jedis = jedisShardInfo.createResource();
                jedis.sadd(TopicRabbitConfig.TRANSACTION_QUEUE, boby);//添加到key為當前消息類型的集合里面,防止丟失消息
                BoluomeFlow flow = gson.fromJson(boby, BoluomeFlow.class);
                String json = gson.toJson(flow);
                if (boluomeFlowService.insert(flow)) {  //當添加成功時候返回成功
                    logger.info("客戶交易流水添加1條記錄:{}", json);
                    jedis.srem(TopicRabbitConfig.TRANSACTION_QUEUE, boby);//從當前消息類型集合中移除已經消費過的消息
                    try {
                        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);//手工返回ACK,通知此消息已經爭取消費
                    } catch (IOException ie) {
                        logger.error("消費成功回調成功,io操作異常");
                    }
                } else {
                    logger.info("客戶交易流水添加失敗記錄:{}", json);
                }
            }
        });
    }
}

channel.basicAck(message.getMessageProperties().getDeliveryTag(), false); // 消息的標識,false只確認當前一個消息收到,true確認所有consumer獲得的消息
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true); // ack返回false,并重新回到隊列,api里面解釋得很清楚

  • channel.basicReject(message.getMessageProperties().getDeliveryTag(), true); // 拒絕消息
    • true 發送給下一個消費者
    • false 誰都不接受,從隊列中刪除
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 為了維護消息的有效性,當消費消息時候處理失敗時候,不進行消費,需要我們根據業務區返回ACK,本項目我使用Redis...
    Chinesszz閱讀 3,512評論 1 0
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,969評論 19 139
  • 本文章翻譯自http://www.rabbitmq.com/api-guide.html,并沒有及時更新。 術語對...
    joyenlee閱讀 7,705評論 0 3
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,422評論 25 708
  • 都說雙魚座最大的特點就是愛幻想 可不幻想點美好 怎么愉快地玩耍下去
    打不死的小花閱讀 195評論 0 0