延迟功能

92 阅读2分钟
  1. 实现方法: 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