规则:用户A给用户B发送一条消息,24小时内如果B回复了A,给B增加消息回复率,超过24小时则扣回复率。

           只拿一个月的回复数据计算,回复率初始值(用户未)为0%。

 


从消息服务器,拿到俩个用户的id,利用redis做会话锁。

思路:比如用户A 给用户B发送一条消息,key值设置为A-B,value为当前时间的时间戳,从redis中查询key值 A-B 或者 B-A 是否存在。

如果A-B存在,不存入reids,因为A已经给B用户发送过信息,只计算A给B发送第一条消息的时间。

如果B-A存在,属于B用户回复A用户的信息,不存入redis

利用spring schedule定时,每隔一段时间取出redis会话锁中所有key,判断时间戳是否超过24小时。

超过24小时,根据时间戳查询数据源,24小时内有没有B回复给A的消息记录。

存在消息记录,存入数据源,表结构:发送者id,接受者id,回复状态,时间戳,删除redis中会话锁,以便计算24小时后用户回复率。之后根据这张表,计算回复率就可以了。数据源我用的mongoDB。

(会话锁也可以利用MQ的延时消息来实现,这样的好处是不依赖定时任务,也避免了每次查redis,那些时间不够24的key的消耗。)

 

/**
     * 计算消息回复率
     */
    public void createSessionLock(IMRouteResponse imRouteResponse){
        //发送人id
        String sendId = imRouteResponse.getFromAccount();
        //接受人id
        String taskId = imRouteResponse.getTo();

        // 查询会话是否已存在
        final String  key = sendId + "-" + taskId;
        final String reverseKey = taskId + "-" + sendId;
        if(!redisTemplate.hasKey(Constants.MESSAGE_REPLY_RATE_LOCK + key) && 
!redisTemplate.hasKey(Constants.MESSAGE_REPLY_RATE_LOCK + reverseKey)){
            // 不存在 创建会话
            redisTemplate.opsForValue().set(Constants.MESSAGE_REPLY_RATE_LOCK + key,System.currentTimeMillis()+"");
            logger.info("【消息回复率】创建{}会话",key);
        }else{
            // 已存在什么都不做
            logger.info("【消息回复率】会话{}已存在!放弃创建会话!",key);
        }


    }

 


定时器

/**
     * 每天计算消息回复率
     */
    @Scheduled(cron = "0 0 0/1 * * ?")
    public void messageReplyRate(){
        userMessageReplyRateService.messageReplyRate();
    }
/**
     * 拿出会话锁中,计算超过24小时的会话的回复率情况
     */
    public void messageReplyRate(){
        Set<String> sessionKey = redisTemplate.keys(Constants.MESSAGE_REPLY_RATE_LOCK + "*");
        for (String keyJson : sessionKey) {
            String timeJson = redisTemplate.opsForValue().get(keyJson);
            // 此时间+24小时是否超过 当前时间
            long currentTimeMillis = System.currentTimeMillis();
            Long start = Long.valueOf(timeJson) + (1000 * 60 /* 24*/);
            if(start < currentTimeMillis){
                //MESSAGE_REPLY_RATE_LOCK:12-62
                String[] split = keyJson.split(":");
                //12-62
                String key = split[1];
                String[] split1 = key.split("-");
                // 查询mongo 收信人在 timeJson 之后  有没有给发件人 回复
                String send = split1[0];
                String task = split1[1];
                // 查询 接收方之后的24小时里有没有给发送方 回信息
                logger.info("【消息回复率】id:" + send + "用户给id:" + task + "用户发送的消息已超过24小时。");
                ReturnConstants rc = imHistoryRecordService.queryHistoryByUserAndTime(task, send, Long.valueOf(timeJson));
                if(ReturnConstants.SUCCESS == rc){
                    //删除会话锁
                    redisTemplate.delete(Constants.MESSAGE_REPLY_RATE_LOCK + key);
                }else{
                    //这条记录没被正确保存mongo,判断一下 如果时间戳超过 26小时,意味着它失败了两次,就删掉吧。
                    if((NumberUtils.toInt(timeJson) + (1000 * 60 * 26) > currentTimeMillis)){
                        redisTemplate.delete(Constants.MESSAGE_REPLY_RATE_LOCK + key);
                    }

                }
            }
        }
/**
     * 查询历史记录,这个时间段之后的24小时,双方之间有没有通信
     * @param send
     * @param task
     * @param currentTimeMillis
     */
    public ReturnConstants queryHistoryByUserAndTime(String send, String task, long currentTimeMillis) {
        logger.info("【消息回复率】查询mongo,发送人Id:{},接受人id:{},在{}后24小时中。",send,task, Dates.formatTimeMillis(currentTimeMillis,"yyyy-MM-dd HH:mm:ss"));
        Criteria criteria = new Criteria();
        criteria.and("fromAccount").is(send);
        criteria.and("to").is(task);
        //条件查询2,gte大于 lte小于
        criteria.and("msgTimestamp").gte(currentTimeMillis).lte(currentTimeMillis + 1000 * 60 * 24);
        Query query = new Query(criteria);
        long count = mongoTemplate.count(query, IMRouteResponse.class);
        UserMessageReplyRate umrr = new UserMessageReplyRate();
        if(count > 0){
            // 双方有过通信
            umrr.setReplyUserId(NumberUtils.toInt(task));
            umrr.setToUserid(NumberUtils.toInt(send));
            umrr.setState(1);//是否回复成功 1:回复者回复了消息 2:回复者没有回复消息
            umrr.setTimeline(System.currentTimeMillis());
            logger.info("【消息回复率】回复人id{},被回复人id{},在24小时内,回复了消息");
        }else{
            umrr.setReplyUserId(NumberUtils.toInt(task));
            umrr.setToUserid(NumberUtils.toInt(send));
            umrr.setState(2);//是否回复成功 1:回复者回复了消息 2:回复者没有回复消息
            umrr.setTimeline(System.currentTimeMillis());
            logger.info("【消息回复率】回复人id{},被回复人id{},在24小时内,没有回复消息");
        }
        return imUserMessageReplyService.saveUserMessageReplyRate(umrr);
    }