ProjectFlusher.coffee 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. request = require("request")
  2. Settings = require('settings-sharelatex')
  3. RedisManager = require("./RedisManager")
  4. rclient = RedisManager.rclient
  5. docUpdaterKeys = Settings.redis.documentupdater.key_schema
  6. async = require("async")
  7. ProjectManager = require("./ProjectManager")
  8. _ = require("lodash")
  9. ProjectFlusher =
  10. # iterate over keys asynchronously using redis scan (non-blocking)
  11. # handle all the cluster nodes or single redis server
  12. _getKeys: (pattern, limit, callback) ->
  13. nodes = rclient.nodes?('master') || [ rclient ];
  14. doKeyLookupForNode = (node, cb) ->
  15. ProjectFlusher._getKeysFromNode node, pattern, limit, cb
  16. async.concatSeries nodes, doKeyLookupForNode, callback
  17. _getKeysFromNode: (node, pattern, limit = 1000, callback) ->
  18. cursor = 0 # redis iterator
  19. keySet = {} # use hash to avoid duplicate results
  20. batchSize = if limit? then Math.min(limit, 1000) else 1000
  21. # scan over all keys looking for pattern
  22. doIteration = (cb) ->
  23. node.scan cursor, "MATCH", pattern, "COUNT", batchSize, (error, reply) ->
  24. return callback(error) if error?
  25. [cursor, keys] = reply
  26. for key in keys
  27. keySet[key] = true
  28. keys = Object.keys(keySet)
  29. noResults = cursor == "0" # redis returns string results not numeric
  30. limitReached = (limit? && keys.length >= limit)
  31. if noResults || limitReached
  32. return callback(null, keys)
  33. else
  34. setTimeout doIteration, 10 # avoid hitting redis too hard
  35. doIteration()
  36. # extract ids from keys like DocsWithHistoryOps:57fd0b1f53a8396d22b2c24b
  37. # or docsInProject:{57fd0b1f53a8396d22b2c24b} (for redis cluster)
  38. _extractIds: (keyList) ->
  39. ids = for key in keyList
  40. m = key.match(/:\{?([0-9a-f]{24})\}?/) # extract object id
  41. m[1]
  42. return ids
  43. flushAllProjects: (options, callback)->
  44. ProjectFlusher._getKeys docUpdaterKeys.docsInProject({project_id:"*"}), options.limit, (error, project_keys) ->
  45. if error?
  46. logger.err err:error, "error getting keys for flushing"
  47. return callback(error)
  48. project_ids = ProjectFlusher._extractIds(project_keys)
  49. if options.dryRun
  50. return callback(null, project_ids)
  51. jobs = _.map project_ids, (project_id)->
  52. return (cb)->
  53. ProjectManager.flushAndDeleteProjectWithLocks project_id, cb
  54. async.parallelLimit jobs, options.concurrency, (error)->
  55. return callback(error, project_ids)
  56. module.exports = ProjectFlusher