最近自己寫的一個項目中需要實作紅包退還的功能,感覺紅包時間過期然後如果仍未被搶完就需要退還,其中我的方案是使用rabbitmq實作的死信隊列解決的。
關于rabbitmq的簡單使用看我之前的部落格https://blog.csdn.net/weixin_40840879/article/details/92836319
什麼是死信隊列?
在隊列中的消息有兩種情況下會被判斷為死信
1.超過TTL(time to live)設定規定生存時間,也就過期的消息
2.被拒絕的消息(basicreject)并且設定不重新放入隊列(requeue = false)的消息
這時候死信隊列會将死信轉發到新的隊列,對應消費者從中取出消費死信
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPR90MnRUTwcGRNBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3EjN4MzMwIjMwIjNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
也就說消費者監聽 消費隊列 就可以拿到已成為死信的消息并進行消費,我的紅包退還解決方案就是,每當釋出新的紅包時,将紅包id與使用者id存在一個消息并設定過期時間發送給死信隊列,當死信隊列判斷該消息已過期就轉發到消費隊列,再從消費隊列取出消息進行消費也就是判斷sh是否需要退還紅包等業務邏輯操作。
如何配置死信隊列?
配置很簡單,在建立隊列時傳入兩個參數就會成為死信隊列,第一個是将死信轉發到Exchange,第二個是Routing key
map.put("x-dead-letter-exchange", "Test_DEADLETTER_EXCHANGE");
map.put("x-dead-letter-routing-key", "Test_REDIRECT_QUEUE_KEY");
完整建立隊列
@Bean("deadLetterQueueTest")
public Queue directQueue() {
HashMap<String, Object> map = new HashMap<>(2);
//聲明消息變成死信後,交給的交換機和路由鍵
map.put("x-dead-letter-exchange", "Test_DEADLETTER_EXCHANGE");
map.put("x-dead-letter-routing-key", "Test_REDIRECT_QUEUE_KEY");
return QueueBuilder.nonDurable("Test_DEADLETTER_QUEUE").withArguments(map).build();
}
通過設定messagepostprocessor.setExpiration("過期時間")來設定消息的時間期限;
@RequestMapping(value = "/testMq1", method = RequestMethod.POST)
public String test5(String args) {
MessagePostProcessor messagePostProcessor = message -> {
MessageProperties messageProperties = message.getMessageProperties();
messageProperties.setContentEncoding("utf-8");
messageProperties.setExpiration("20000");
return message;
};
rabbitTemplate.convertAndSend("Test_DEADLETTER_EXCHANGE", "TEST_DIRECT_ROUTING_KEY", args, messagePostProcessor);
return "success";
}
另外由于死信隊列是隻在頭部進行判斷是否過期然後進行轉發,也就是如果處于中間位置的消息可能已經過期但也要等前面消息過期轉發掉才會觸發轉發。