diff --git a/services/document-updater/app/coffee/HistoryManager.coffee b/services/document-updater/app/coffee/HistoryManager.coffee index 0c3ab9cea1..7cfafa9ba0 100644 --- a/services/document-updater/app/coffee/HistoryManager.coffee +++ b/services/document-updater/app/coffee/HistoryManager.coffee @@ -28,6 +28,9 @@ module.exports = HistoryManager = # flush changes and callback (for when we need to know the queue is flushed) flushProjectChanges: (project_id, options, callback = (error) ->) -> return callback() if !Settings.apis?.project_history?.enabled + if options.skip_history_flush + logger.log {project_id}, "skipping flush of project history from realtime shutdown" + return callback() url = "#{Settings.apis.project_history.url}/project/#{project_id}/flush" qs = {} qs.background = true if options.background # pass on the background flush option if present diff --git a/services/document-updater/app/coffee/HttpController.coffee b/services/document-updater/app/coffee/HttpController.coffee index b35943f5cd..d2ef5043d0 100644 --- a/services/document-updater/app/coffee/HttpController.coffee +++ b/services/document-updater/app/coffee/HttpController.coffee @@ -133,6 +133,7 @@ module.exports = HttpController = timer = new Metrics.Timer("http.deleteProject") options = {} options.background = true if req.query?.background # allow non-urgent flushes to be queued + options.skip_history_flush = true if req.query?.shutdown # don't flush history when realtime shuts down ProjectManager.flushAndDeleteProjectWithLocks project_id, options, (error) -> timer.done() return next(error) if error? diff --git a/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.coffee b/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.coffee index 7a5eed5691..cb1d3495d8 100644 --- a/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.coffee +++ b/services/document-updater/test/acceptance/coffee/DeletingAProjectTests.coffee @@ -41,17 +41,15 @@ describe "Deleting a project", -> version: doc.update.v } - sinon.spy MockTrackChangesApi, "flushDoc" - sinon.spy MockProjectHistoryApi, "flushProject" DocUpdaterApp.ensureRunning(done) - after -> - MockTrackChangesApi.flushDoc.restore() - MockProjectHistoryApi.flushProject.restore() describe "with documents which have been updated", -> before (done) -> sinon.spy MockWebApi, "setDocument" + sinon.spy MockTrackChangesApi, "flushDoc" + sinon.spy MockProjectHistoryApi, "flushProject" + async.series @docs.map((doc) => (callback) => DocUpdaterClient.preloadDoc @project_id, doc.id, (error) => @@ -68,6 +66,8 @@ describe "Deleting a project", -> after -> MockWebApi.setDocument.restore() + MockTrackChangesApi.flushDoc.restore() + MockProjectHistoryApi.flushProject.restore() it "should return a 204 status code", -> @statusCode.should.equal 204 @@ -96,3 +96,42 @@ describe "Deleting a project", -> it "should flush each doc in project history", -> MockProjectHistoryApi.flushProject.calledWith(@project_id).should.equal true + + describe "with the shutdown=true parameter from realtime", -> + before (done) -> + sinon.spy MockWebApi, "setDocument" + sinon.spy MockTrackChangesApi, "flushDoc" + sinon.spy MockProjectHistoryApi, "flushProject" + + async.series @docs.map((doc) => + (callback) => + DocUpdaterClient.preloadDoc @project_id, doc.id, callback + ), (error) => + throw error if error? + setTimeout () => + DocUpdaterClient.deleteProjectOnShutdown @project_id, (error, res, body) => + @statusCode = res.statusCode + done() + , 200 + + after -> + MockWebApi.setDocument.restore() + MockTrackChangesApi.flushDoc.restore() + MockProjectHistoryApi.flushProject.restore() + + it "should return a 204 status code", -> + @statusCode.should.equal 204 + + it "should send each document to the web api", -> + for doc in @docs + MockWebApi.setDocument + .calledWith(@project_id, doc.id, doc.updatedLines) + .should.equal true + + it "should flush each doc in track changes", -> + for doc in @docs + MockTrackChangesApi.flushDoc.calledWith(doc.id).should.equal true + + it "should not flush to project history", -> + MockProjectHistoryApi.flushProject.called.should.equal false + diff --git a/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.coffee b/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.coffee index 82dba20685..9525cc27e9 100644 --- a/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.coffee +++ b/services/document-updater/test/acceptance/coffee/helpers/DocUpdaterClient.coffee @@ -75,6 +75,9 @@ module.exports = DocUpdaterClient = deleteProject: (project_id, callback = () ->) -> request.del "http://localhost:3003/project/#{project_id}", callback + deleteProjectOnShutdown: (project_id, callback = () ->) -> + request.del "http://localhost:3003/project/#{project_id}?background=true&shutdown=true", callback + acceptChange: (project_id, doc_id, change_id, callback = () ->) -> request.post "http://localhost:3003/project/#{project_id}/doc/#{doc_id}/change/#{change_id}/accept", callback diff --git a/services/document-updater/test/unit/coffee/HistoryManager/HistoryManagerTests.coffee b/services/document-updater/test/unit/coffee/HistoryManager/HistoryManagerTests.coffee index 1198bf7c7b..07c3577a91 100644 --- a/services/document-updater/test/unit/coffee/HistoryManager/HistoryManagerTests.coffee +++ b/services/document-updater/test/unit/coffee/HistoryManager/HistoryManagerTests.coffee @@ -46,6 +46,28 @@ describe "HistoryManager", -> .calledWith({url: "#{@Settings.apis.project_history.url}/project/#{@project_id}/flush", qs:{background:true}}) .should.equal true + describe "flushProjectChanges", -> + + describe "in the normal case", -> + beforeEach -> + @request.post = sinon.stub().callsArgWith(1, null, statusCode: 204) + @HistoryManager.flushProjectChanges @project_id, {background:true} + + it "should send a request to the project history api", -> + @request.post + .calledWith({url: "#{@Settings.apis.project_history.url}/project/#{@project_id}/flush", qs:{background:true}}) + .should.equal true + + describe "with the skip_history_flush option", -> + beforeEach -> + @request.post = sinon.stub() + @HistoryManager.flushProjectChanges @project_id, {skip_history_flush:true} + + it "should not send a request to the project history api", -> + @request.post + .called + .should.equal false + describe "recordAndFlushHistoryOps", -> beforeEach -> @ops = [ 'mock-ops' ] diff --git a/services/document-updater/test/unit/coffee/HttpController/HttpControllerTests.coffee b/services/document-updater/test/unit/coffee/HttpController/HttpControllerTests.coffee index 6429a4031d..c1f5c5eca8 100644 --- a/services/document-updater/test/unit/coffee/HttpController/HttpControllerTests.coffee +++ b/services/document-updater/test/unit/coffee/HttpController/HttpControllerTests.coffee @@ -343,6 +343,17 @@ describe "HttpController", -> it "should time the request", -> @Metrics.Timer::done.called.should.equal true + describe "with the shutdown=true option from realtime", -> + beforeEach -> + @ProjectManager.flushAndDeleteProjectWithLocks = sinon.stub().callsArgWith(2) + @req.query = {background:true, shutdown:true} + @HttpController.deleteProject(@req, @res, @next) + + it "should pass the skip_history_flush option when flushing the project", -> + @ProjectManager.flushAndDeleteProjectWithLocks + .calledWith(@project_id, {background:true, skip_history_flush:true}) + .should.equal true + describe "when an errors occurs", -> beforeEach -> @ProjectManager.flushAndDeleteProjectWithLocks = sinon.stub().callsArgWith(2, new Error("oops"))