Ver Fonte

add a timeout for getPreviousDocOps

it uses several redis operations and this makes it prone to subsequent
timeouts if getDoc succeeds but is slow
Brian Gough há 9 anos atrás
pai
commit
963e513057

+ 3 - 0
services/document-updater/app/coffee/RedisManager.coffee

@@ -141,6 +141,7 @@ module.exports = RedisManager =
 			callback null, version
 
 	getPreviousDocOps: (doc_id, start, end, callback = (error, jsonOps) ->) ->
+		timer = new metrics.Timer("redis.get-prev-docops")
 		rclient.llen keys.docOps(doc_id: doc_id), (error, length) ->
 			return callback(error) if error?
 			rclient.get keys.docVersion(doc_id: doc_id), (error, version) ->
@@ -168,6 +169,8 @@ module.exports = RedisManager =
 						ops = jsonOps.map (jsonOp) -> JSON.parse jsonOp
 					catch e
 						return callback(e)
+					timeSpan = timer.done()
+					return callback(new Error("redis getPreviousDocOps exceeded timeout")) if timeSpan > MAX_REDIS_REQUEST_LENGTH
 					callback null, ops
 
 	DOC_OPS_TTL: 60 * minutes

+ 29 - 0
services/document-updater/test/unit/coffee/RedisManager/RedisManagerTests.coffee

@@ -265,6 +265,35 @@ describe "RedisManager", ->
 			it "should log out the problem", ->
 				@logger.warn.called.should.equal true
 
+		describe "with a slow request to redis", ->
+			beforeEach ->
+				@first_version_in_redis = 30
+				@version = 70
+				@length = @version - @first_version_in_redis
+				@start  = 50
+				@end    = 60
+				@ops = [
+					{ "mock": "op-1" },
+					{ "mock": "op-2" }
+				]
+				@jsonOps = @ops.map (op) -> JSON.stringify op
+				@rclient.llen = sinon.stub().callsArgWith(1, null, @length)
+				@rclient.get = sinon.stub().callsArgWith(1, null, @version.toString())
+				@clock = sinon.useFakeTimers();
+				@rclient.lrange = (key, start, end, cb) =>
+					@clock.tick(6000);
+					cb(null, @jsonOps)
+				@RedisManager.getPreviousDocOps(@doc_id, @start, @end, @callback)
+
+			afterEach ->
+				@clock.restore()
+
+			it 'should return an error', ->
+				@callback
+					.calledWith(new Error("redis getPreviousDocOps exceeded timeout"))
+					.should.equal true
+
+
 	describe "updateDocument", ->
 		beforeEach ->
 			@rclient.set = sinon.stub()