MQ消息延迟推送

场景:推送门店昨日销售业绩给各个门店店长,数据提供方来自大数据,正常情况下是9点出数据,但是处理时可能会延迟有可能9点2分,9点5分甚至是9点30分还未出数据,后端程序每天9点定时任务推送数据,如果推送时从大数据接口获取不到数据,那么整天的数据就需要人为干涉手动推送,十分的不人性化。

解决方案:通过MQ的死信队列+消息过期时间,实现无数据时5分钟后重新推送,超过N次后将为推送的门店入库,发送消息(邮件)告知管理员。

流程图

在这里插入图片描述

代码

通过SpringBoot+RabbitMQ实现

1 申明交换机,消息队列,绑定规则

@Configuration
public class RabbitConfig {

    /**
     * 交换机
     */
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange("message-exchange",true,false);
    }

    /**
     * 死信队列设置过期时间,过期消息重新发送给消息队列
     * @return
     */
    @Bean
    public Queue deadQueue(){
        QueueBuilder queue = QueueBuilder.durable("deadQueue");

        queue.deadLetterExchange("message-exchange");
        queue.deadLetterRoutingKey("message");
        queue.ttl((int)Duration.ofMinutes(5).toMillis());

        return queue.build();
    }

    /**
     * 消息队列绑定死信交换机和队列
     * */
    @Bean
    public Queue message(){
        QueueBuilder queue = QueueBuilder.durable("message");

        queue.deadLetterExchange("message-exchange");
        queue.deadLetterRoutingKey("deadQueue");
        return queue.build();
    }

    /**
     * 绑定规则
     */
    @Bean
    public Binding binding(){
        return BindingBuilder.bind( deadQueue() ).to(directExchange()).with("deadQueue");
    }

    /**
     * 绑定规则
     */
    @Bean
    public Binding binding2(){
        return BindingBuilder.bind( message() ).to(directExchange()).with("message");
    }

}

消费者代码

@Component
public class MessageListener {

    private static final int retryCnt = 5;
    private Logger logger = LoggerFactory.getLogger( MessageListener.class );

    //模拟redis缓存
    private ConcurrentHashMap<String, AtomicInteger> cache = new ConcurrentHashMap(8);

    @RabbitListener(queues = "message")
    public void listener(Message message, Channel channel, @Headers Map<String,Object> map, @Payload Integer body) throws IOException {
        //如果是奇数直接消费
        if( body%2 != 0 ){
            channel.basicAck( message.getMessageProperties().getDeliveryTag(),false );
            logger.info("成功消费消息");
            return;
        }

        //这里主要用户删掉消费5次的消息
        if( get(body) > retryCnt ){
            channel.basicAck( message.getMessageProperties().getDeliveryTag(),false );
            logger.error("删除消息"+body);
            return;
        }

        logger.error("当前消息{},消费第 {} 次,无数据返回,3秒钟后重试",body, get(body));
        channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
        incr(body);

        if( get(body) >retryCnt ){
            logger.error("消息超过最大消费次数{},入库并发送邮件通知-->{}",retryCnt,body);
        }

    }


    public int incr(Integer num){
        String key = StrUtil.toString( num );

        if( cache.get( key ) == null ){
            cache.put( key ,new AtomicInteger(1) );
        }
        return cache.get( key ).incrementAndGet();
    }

    public Integer get(Integer num){
        String key = StrUtil.toString( num );

        if( cache.get( key ) == null ){
            cache.put( key ,new AtomicInteger(1) );
        }
        return cache.get( key ).get();
    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值