Ver Fonte

Merge pull request #33 from sharelatex/bg-add-timestamp-marker-to-project-history-queue

set a timestamp for the first entry in the projectHistory:Ops queue (connects to overleaf/sharelatex#658)
Brian Gough há 8 anos atrás
pai
commit
c4f1e27627

+ 12 - 2
services/document-updater/app/coffee/ProjectHistoryRedisManager.coffee

@@ -4,8 +4,18 @@ rclient = require("redis-sharelatex").createClient(Settings.redis.documentupdate
 logger = require('logger-sharelatex')
 
 module.exports = ProjectHistoryRedisManager =
-	queueOps: (project_id, ops..., callback) ->
-		rclient.rpush projectHistoryKeys.projectHistoryOps({project_id}), ops..., callback
+	queueOps: (project_id, ops..., callback = (error, projectUpdateCount) ->) ->
+		multi = rclient.multi()
+		# Push the ops onto the project history queue
+		multi.rpush projectHistoryKeys.projectHistoryOps({project_id}), ops...
+		# To record the age of the oldest op on the queue set a timestamp if not
+		# already present (SETNX).
+		multi.setnx projectHistoryKeys.projectHistoryFirstOpTimestamp({project_id}), Date.now()
+		multi.exec (error, result) ->
+			return callback(error) if error?
+			# return the number of entries pushed onto the project history queue
+			callback null, result[0]
+
 
 	queueRenameEntity: (project_id, projectHistoryId, entity_type, entity_id, user_id, projectUpdate, callback) ->
 		projectUpdate =

+ 1 - 0
services/document-updater/config/settings.defaults.coffee

@@ -74,6 +74,7 @@ module.exports =
 		project_history:
 			key_schema:
 				projectHistoryOps: ({project_id}) -> "ProjectHistory:Ops:#{project_id}"
+				projectHistoryFirstOpTimestamp: ({project_id}) -> "ProjectHistory:FirstOpTimestamp:#{project_id}"
 			# cluster: [{
 			# 	port: "7000"
 			# 	host: "localhost"

+ 22 - 1
services/document-updater/test/acceptance/coffee/ApplyingUpdatesToADocTests.coffee

@@ -33,7 +33,7 @@ describe "Applying updates to a doc", ->
 		before (done) ->
 			[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]
 			sinon.spy MockWebApi, "getDocument"
-
+			@startTime = Date.now()
 			MockWebApi.insertDoc @project_id, @doc_id, {lines: @lines, version: @version}
 			DocUpdaterClient.sendUpdate @project_id, @doc_id, @update, (error) ->
 				throw error if error?
@@ -67,6 +67,27 @@ describe "Applying updates to a doc", ->
 				JSON.parse(updates[0]).op.should.deep.equal @update.op
 				done()
 
+		it "should set the first op timestamp", (done) ->
+			rclient_history.get ProjectHistoryKeys.projectHistoryFirstOpTimestamp({@project_id}), (error, result) =>
+				throw error if error?
+				result.should.be.within(@startTime, Date.now())
+				@firstOpTimestamp = result
+				done()
+
+		describe "when sending another update", ->
+			before (done) ->
+				@second_update = Object.create(@update)
+				@second_update.v = @version + 1
+				DocUpdaterClient.sendUpdate @project_id, @doc_id, @second_update, (error) ->
+					throw error if error?
+					setTimeout done, 200
+
+			it "should not change the first op timestamp", (done) ->
+				rclient_history.get ProjectHistoryKeys.projectHistoryFirstOpTimestamp({@project_id}), (error, result) =>
+					throw error if error?
+					result.should.equal @firstOpTimestamp
+					done()
+
 	describe "when the document is loaded", ->
 		before (done) ->
 			[@project_id, @doc_id] = [DocUpdaterClient.randomId(), DocUpdaterClient.randomId()]

+ 14 - 3
services/document-updater/test/unit/coffee/ProjectHistoryRedisManager/ProjectHistoryRedisManagerTests.coffee

@@ -20,6 +20,7 @@ describe "ProjectHistoryRedisManager", ->
 						project_history:
 							key_schema:
 								projectHistoryOps: ({project_id}) -> "ProjectHistory:Ops:#{project_id}"
+								projectHistoryFirstOpTimestamp: ({project_id}) -> "ProjectHistory:FirstOpTimestamp:#{project_id}"
 				}
 				"redis-sharelatex":
 					createClient: () => @rclient
@@ -32,16 +33,26 @@ describe "ProjectHistoryRedisManager", ->
 	describe "queueOps", ->
 		beforeEach ->
 			@ops = ["mock-op-1", "mock-op-2"]
-			@rclient.rpush = sinon.stub()
+			@multi = exec: sinon.stub()
+			@multi.rpush = sinon.stub()
+			@multi.setnx = sinon.stub()
+			@rclient.multi = () => @multi
+			# @rclient = multi: () => @multi
 			@ProjectHistoryRedisManager.queueOps @project_id, @ops..., @callback
 
 		it "should queue an update", ->
-			@rclient.rpush
+			@multi.rpush
 				.calledWithExactly(
 					"ProjectHistory:Ops:#{@project_id}"
 					@ops[0]
 					@ops[1]
-					@callback
+				).should.equal true
+
+		it "should set the queue timestamp if not present", ->
+			@multi.setnx
+				.calledWithExactly(
+					"ProjectHistory:FirstOpTimestamp:#{@project_id}"
+					Date.now()
 				).should.equal true
 
 	describe "queueRenameEntity", ->