规则:用户 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); }
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于