/** * Redis会话清除器。会话清理暂时不使用。 * * Redis中的会话有效期为40分钟,即自会话中最后一次时间算起,如果40分钟内没有成员发送、读取消息则将此会话从内存中清除。 * 为减少冲突,每次只清理时间最久的前10个会话。 * * 清理逻辑:首先检查哪些会话是过期的,取得前10个过期会话,然后取得会话中的消息、MUC议题、成员列表、成员信息及客户端状态,将这些内容全部删除。 * * PS: 目前此策略有一个问题:在并发量大的时候,有可能在清理时,刚好用户在登录,此时会发生冲突。 * * author: Sand * since: 12/23/2016 */ "use strict"; let RedisModel = require('../redis.model'); let RedisClient = require('../../repository/redis/redis.client.js'); let async = require('async'); let configFile = require('../../include/commons').CONFIG_FILE; let config = require('../../resources/config/' + configFile); let redis = RedisClient.redisClient().connection; let log = require('../../util/log'); const REDIS_KEYS = require('../../include/commons').REDIS_KEYS; class SessionCleaner { constructor() { } /** * 清理过期会话,但目前不能清理用户信息,因为用户可能在其他活动的会话中, * 除非后续有对每个用户做会话引用,便可以在清除会话时根据引用数量清理用户信息, * 因此当前有以下内容不清理: * users: * users:user_id * users:user_id:sessions * users:user_id:app_status * users:user_id:wechat_status * * @param count 清理多少个 */ static cleanExpiredSessions(count) { let baseScore = new Date().getMilliseconds() - config.sessionConfig.expireTime; let sessionsKey = RedisModel.makeRedisKey(REDIS_KEYS.Sessions); redis.zrevrangebyscoreAsync(sessionsKey, baseScore, config.MAX_INT).then(function (sessionIds) { if (sessionIds.length > count) { sessionIds = sessionIds.splice(count, sessionIds.length - count); } // 构建对每个会话的清理操作 let sessionCleanCalls = []; sessionIds.forEach(function (sessionId) { sessionCleanCalls.push(function (callback) { let topicsKey = RedisModel.makeRedisKey(REDIS_KEYS.Topics, sessionId); // 清理议题 redis.zrangeAsync(topicsKey, 0, -1).then(function (topicIds) { redis.del(topicIds.forEach(function (topicId) { return RedisModel.makeRedisKey(REDIS_KEYS.Topic, topicId); })); }); // 清理会话、议题、参与者、消息 let toDeleteKeys = [REDIS_KEYS.Sessions, REDIS_KEYS.Session, REDIS_KEYS.Topics, REDIS_KEYS.SessionParticipantsRole, REDIS_KEYS.SessionParticipants, REDIS_KEYS.Messages, REDIS_KEYS.MessagesByTimestamp]; redis.del(toDeleteKeys.forEach(function (key) { return RedisModel.makeRedisKey(key, sessionId); })); }); }); async.parallel(sessionCleanCalls, function (err, result) { if (err) log.error("Clean redis session failed: ", err); log.info(result); }); }) } } module.exports = SessionCleaner;