mirror of
https://github.com/overleaf/overleaf.git
synced 2025-04-15 16:37:28 +00:00
Include ioredis as a driver to be able to handle cluster configs
This commit is contained in:
parent
3334a55944
commit
3b58e390fd
2 changed files with 62 additions and 43 deletions
|
@ -13,53 +13,71 @@ module.exports = RedisSharelatex =
|
|||
delete standardOpts.endpoints
|
||||
delete standardOpts.masterName
|
||||
client = require("redis-sentinel").createClient opts.endpoints, opts.masterName, standardOpts
|
||||
client.healthCheck = RedisSharelatex.singleInstanceHealthCheckBuilder(client)
|
||||
else if opts.cluster?
|
||||
Redis = require("ioredis")
|
||||
client = new Redis.Cluster(opts.cluster)
|
||||
client.healthCheck = RedisSharelatex.clusterHealthCheckBuilder(client)
|
||||
RedisSharelatex._monkeyPatchIoredisExec(client)
|
||||
else
|
||||
standardOpts = _.clone(opts)
|
||||
delete standardOpts.port
|
||||
delete standardOpts.host
|
||||
client = require("redis").createClient opts.port, opts.host, standardOpts
|
||||
client.healthCheck = RedisSharelatex.singleInstanceHealthCheckBuilder(client)
|
||||
return client
|
||||
|
||||
|
||||
activeHealthCheckRedis: (connectionInfo)->
|
||||
sub = RedisSharelatex.createClient(connectionInfo)
|
||||
pub = RedisSharelatex.createClient(connectionInfo)
|
||||
|
||||
HEARTBEAT_TIMEOUT: 2000
|
||||
singleInstanceHealthCheckBuilder: (client) ->
|
||||
healthCheck = (callback) ->
|
||||
RedisSharelatex._checkClient(client, callback)
|
||||
return healthCheck
|
||||
|
||||
clusterHealthCheckBuilder: (client) ->
|
||||
healthCheck = (callback) ->
|
||||
jobs = client.rclient.nodes("all").map (node) =>
|
||||
(cb) => RedisSharelatex._checkClient(node, cb)
|
||||
async.parallel jobs, callback
|
||||
|
||||
redisIsOk = true
|
||||
lastPingMessage = ""
|
||||
heartbeatInterval = 2000 #ms
|
||||
isAliveTimeout = 10000 #ms
|
||||
return healthCheck
|
||||
|
||||
_checkClient: (client, callback) ->
|
||||
callback = _.once(callback)
|
||||
timer = setTimeout () ->
|
||||
error = new Error("redis client ping check timed out")
|
||||
console.error {
|
||||
err: error,
|
||||
key: client.options?.key # only present for cluster
|
||||
}, "client timed out"
|
||||
callback(error)
|
||||
, RedisSharelatex.HEARTBEAT_TIMEOUT
|
||||
client.ping (err) ->
|
||||
clearTimeout timer
|
||||
callback(err)
|
||||
|
||||
id = require("crypto").pseudoRandomBytes(16).toString("hex")
|
||||
heartbeatChannel = "heartbeat-#{id}"
|
||||
lastHeartbeat = Date.now()
|
||||
_monkeyPatchIoredisExec: (client) ->
|
||||
_multi = client.multi
|
||||
client.multi = (args...) ->
|
||||
multi = _multi.call(client, args...)
|
||||
_exec = multi.exec
|
||||
multi.exec = (args..., callback) ->
|
||||
_exec.call multi, args..., (error, result) ->
|
||||
# ioredis exec returns an results like:
|
||||
# [ [null, 42], [null, "foo"] ]
|
||||
# where the first entries in each 2-tuple are
|
||||
# presumably errors for each individual command,
|
||||
# and the second entry is the result. We need to transform
|
||||
# this into the same result as the old redis driver:
|
||||
# [ 42, "foo" ]
|
||||
filtered_result = []
|
||||
for entry in result or []
|
||||
if entry[0]?
|
||||
return callback(entry[0])
|
||||
else
|
||||
filtered_result.push entry[1]
|
||||
callback error, filtered_result
|
||||
return multi
|
||||
|
||||
|
||||
sub.subscribe heartbeatChannel, (error) ->
|
||||
if error?
|
||||
console.error "ERROR: failed to subscribe to #{heartbeatChannel} channel", error
|
||||
sub.on "message", (channel, message) ->
|
||||
if lastPingMessage == message #we got the same message twice
|
||||
redisIsOk = false
|
||||
lastPingMessage = message
|
||||
if channel == heartbeatChannel
|
||||
lastHeartbeat = Date.now()
|
||||
|
||||
setInterval ->
|
||||
message = "ping:#{Date.now()}"
|
||||
pub.publish heartbeatChannel, message
|
||||
, heartbeatInterval
|
||||
|
||||
|
||||
isAlive = ->
|
||||
timeSinceLastHeartbeat = Date.now() - lastHeartbeat
|
||||
if !redisIsOk
|
||||
return false
|
||||
else if timeSinceLastHeartbeat > isAliveTimeout
|
||||
console.error "heartbeat from redis timed out"
|
||||
redisIsOk = false
|
||||
return false
|
||||
else
|
||||
return true
|
||||
|
||||
return {
|
||||
isAlive:isAlive
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"name": "redis-sharelatex",
|
||||
"version": "0.0.9",
|
||||
"description": "redis wrapper for node which will either use sentinal or normal redis",
|
||||
"version": "1.0.0",
|
||||
"description": "Redis wrapper for node which will either use cluster, sentinal, or single instance redis",
|
||||
"main": "index.js",
|
||||
"author": "henry oswald @ sharelatex",
|
||||
"author": "ShareLaTeX",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"chai": "1.9.1",
|
||||
|
@ -11,6 +11,7 @@
|
|||
"grunt": "0.4.5",
|
||||
"grunt-contrib-coffee": "0.11.1",
|
||||
"grunt-mocha-test": "0.12.0",
|
||||
"ioredis": "^2.5.0",
|
||||
"mocha": "1.21.4",
|
||||
"redis": "0.12.1",
|
||||
"redis-sentinel": "0.1.1",
|
||||
|
|
Loading…
Add table
Reference in a new issue