- 实现方法: 1.1 rabbitmq
/**
*死信队列实现延迟队列
*/
@Configuration
public class AutoMQConfig {
@Bean
public Exchange deadExchange()
{
// 创建死信队列交换机
return ExchangeBuilder.topicExchange(DEAD_EXCHANGE).build();
}
/**
* 死信队列
* @return
*/
@Bean
public Queue deadQueue()
{
// 创建死信队列
return QueueBuilder.durable(DEAD_QUEUE).build();
}
/**
* 死信交换机绑定死信队列
* @param deadExchange
* @param deadQueue
* @return
*/
@Bean
public Binding deadBinding(Exchange deadExchange,Queue deadQueue)
{
// 死信交换机绑定死信队列
return BindingBuilder.bind(deadQueue).to(deadExchange).with(DEAD_ROUTE).noargs();
}
/**
* 绑定死信交换机及路由key(该正常队列内的消息无法被正常消费时,会转发给绑定的死信交换机通过路由key转发到死信队列)
*/
@Bean
public Queue normalQueue()
{
// 创建队列
return QueueBuilder.durable(NORMAL_QUEUE)
.deadLetterExchange(DEAD_EXCHANGE)// 绑定死信队列交换机
.deadLetterRoutingKey(DEAD_ROUTE)// 绑定死信队列路由
.ttl(30000)// 设置消息过期时间
.build();
}
/**
* 正常队列交换机
*/
@Bean
public DirectExchange normalExchange()
{
// 创建交换机
return ExchangeBuilder.topicExchange(DEAD_EXCHANGE).build();
}
/**
* 正常交换机绑定正常队列
*/
@Bean
public Binding binding(Queue normalQueue,Exchange normalExchange)
{
// 将 队列 交换机 路由key绑定到一起。
return BindingBuilder.bind(normalQueue).to(normalExchange).with(NORMAL_ROUTE).noargs();
}//*/
}
/**
*延迟插件实现延迟队列
*/
@Configuration
public class AutoBiddingConfig {
@Bean
public Exchange deadExchange() {
return ExchangeBuilder.topicExchange(deadExchange)
.durable(true)
.delayed()
.build();
}
/**
* 队列
* @return
*/
@Bean
public Queue deadQueue()
{
// 创建死信队列
return QueueBuilder.durable(deadQueue).build();
}
/**
* 交换机绑定队列
* @param deadExchange
* @param deadQueue
* @return
*/
@Bean
public Binding deadBinding(Exchange deadExchange,Queue deadQueue)
{
// 死信交换机绑定死信队列
return BindingBuilder.bind(deadQueue).to(deadExchange).with(DEAD_ROUTE).noargs();
}
/**
*发送消息
*/
rabbitTemplate.convertAndSend(
deadExchange,
DEAD_ROUTE,
message
//延迟队列插件发送
,
new MessagePostProcessor() {
@Override
public org.springframework.amqp.core.Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
message.getMessageProperties().setDelay(Integer.parseInt(ttlTime));
return message;
}
});
/**
*监听消息
*/
@Component
@Slf4j
public class AutoBiddingDepositReturnListener {
@Autowired
private BiddingDepositReturnApplyService biddingDepositReturnApplyService;
@RabbitListener(queues = AutoBiddingDepositReturnMQConstant.AUTO_BIDDING_DEPOSIT_RETURN_QUEUE)
public void autoBiddingDepositReturn(String message, Channel channel, Message msg) {
==========================
try {
//更改状态
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
log.error("超时自动确认 - 消息id:{}手动ack确认失败", msg.getMessageProperties().getDeliveryTag());
try {
channel.basicReject(msg.getMessageProperties().getDeliveryTag(), true);
} catch (IOException ioException) {
log.error("超时自动确认 - 超时自动确认消息id:{}手动reject放回队列失败", msg.getMessageProperties().getDeliveryTag());
ioException.printStackTrace();
}
}
}
}
3.2 redis
import redis.clients.jedis.Jedis;
public class DelayQueueWithRedis {
private Jedis jedis;
private static final String QUEUE_KEY = "delay_queue";
public DelayQueueWithRedis(Jedis jedis) {
this.jedis = jedis;
}
public void push(String message, long delaySeconds) {
long score = System.currentTimeMillis() / 1000 + delaySeconds;
jedis.zadd(QUEUE_KEY, score, message);
}
public void processMessages() {
long now = System.currentTimeMillis() / 1000;
// 获取所有延迟时间已到的消息
Set<String> messages = jedis.zrangeByScore(QUEUE_KEY, 0, now, 0, 100);
for (String message : messages) {
// 处理消息
System.out.println("Processing message: " + message);
// 处理完后从队列中移除
jedis.zrem(QUEUE_KEY, message);
}
}
public static void main(String[] args) {
Jedis jedis = new Jedis("localhost");
DelayQueueWithRedis delayQueue = new DelayQueueWithRedis(jedis);
// 添加消息
delayQueue.push("message1", 10); // 10秒后处理
delayQueue.push("message2", 30); // 30秒后处理
// 循环处理消息
while (true) {
delayQueue.processMessages();
try {
Thread.sleep(1000); // 每秒检查一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
3.3 定时任务轮询
3. 注意事项: 2.1 幂等性 2.2