session.cleaner.js 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /**
  2. * Redis会话清除器。会话清理暂时不使用。
  3. *
  4. * Redis中的会话有效期为40分钟,即自会话中最后一次时间算起,如果40分钟内没有成员发送、读取消息则将此会话从内存中清除。
  5. * 为减少冲突,每次只清理时间最久的前10个会话。
  6. *
  7. * 清理逻辑:首先检查哪些会话是过期的,取得前10个过期会话,然后取得会话中的消息、MUC议题、成员列表、成员信息及客户端状态,将这些内容全部删除。
  8. *
  9. * PS: 目前此策略有一个问题:在并发量大的时候,有可能在清理时,刚好用户在登录,此时会发生冲突。
  10. *
  11. * author: Sand
  12. * since: 12/23/2016
  13. */
  14. "use strict";
  15. let RedisModel = require('../redis.model');
  16. let RedisClient = require('../../repository/redis/redis.client.js');
  17. let async = require('async');
  18. let configFile = require('../../include/commons').CONFIG_FILE;
  19. let config = require('../../resources/config/' + configFile);
  20. let redis = RedisClient.redisClient().connection;
  21. let log = require('../../util/log');
  22. const REDIS_KEYS = require('../../include/commons').REDIS_KEYS;
  23. class SessionCleaner {
  24. constructor() {
  25. }
  26. /**
  27. * 清理过期会话,但目前不能清理用户信息,因为用户可能在其他活动的会话中,
  28. * 除非后续有对每个用户做会话引用,便可以在清除会话时根据引用数量清理用户信息,
  29. * 因此当前有以下内容不清理:
  30. * users:
  31. * users:user_id
  32. * users:user_id:sessions
  33. * users:user_id:app_status
  34. * users:user_id:wechat_status
  35. *
  36. * @param count 清理多少个
  37. */
  38. static cleanExpiredSessions(count) {
  39. let baseScore = new Date().getMilliseconds() - config.sessionConfig.expireTime;
  40. let sessionsKey = RedisModel.makeRedisKey(REDIS_KEYS.Sessions);
  41. redis.zrevrangebyscoreAsync(sessionsKey, baseScore, config.MAX_INT).then(function (sessionIds) {
  42. if (sessionIds.length > count) {
  43. sessionIds = sessionIds.splice(count, sessionIds.length - count);
  44. }
  45. // 构建对每个会话的清理操作
  46. let sessionCleanCalls = [];
  47. sessionIds.forEach(function (sessionId) {
  48. sessionCleanCalls.push(function (callback) {
  49. let topicsKey = RedisModel.makeRedisKey(REDIS_KEYS.Topics, sessionId);
  50. // 清理议题
  51. redis.zrangeAsync(topicsKey, 0, -1).then(function (topicIds) {
  52. redis.del(topicIds.forEach(function (topicId) {
  53. return RedisModel.makeRedisKey(REDIS_KEYS.Topic, topicId);
  54. }));
  55. });
  56. // 清理会话、议题、参与者、消息
  57. let toDeleteKeys = [REDIS_KEYS.Sessions, REDIS_KEYS.Session, REDIS_KEYS.Topics,
  58. REDIS_KEYS.SessionParticipantsRole, REDIS_KEYS.SessionParticipants, REDIS_KEYS.Messages, REDIS_KEYS.MessagesByTimestamp];
  59. redis.del(toDeleteKeys.forEach(function (key) {
  60. return RedisModel.makeRedisKey(key, sessionId);
  61. }));
  62. });
  63. });
  64. async.parallel(sessionCleanCalls, function (err, result) {
  65. if (err) log.error("Clean redis session failed: ", err);
  66. log.info(result);
  67. });
  68. })
  69. }
  70. }
  71. module.exports = SessionCleaner;