mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 17:23:48 -05:00
Merge pull request #64 from overleaf/bg-downgrade-delete-component-error
downgrade delete component error
This commit is contained in:
commit
6eba954b52
7 changed files with 68 additions and 21 deletions
|
@ -9,3 +9,4 @@ License
|
||||||
The code in this repository is released under the GNU AFFERO GENERAL PUBLIC LICENSE, version 3. A copy can be found in the `LICENSE` file.
|
The code in this repository is released under the GNU AFFERO GENERAL PUBLIC LICENSE, version 3. A copy can be found in the `LICENSE` file.
|
||||||
|
|
||||||
Copyright (c) Overleaf, 2014-2019.
|
Copyright (c) Overleaf, 2014-2019.
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ module.exports = DispatchManager =
|
||||||
# log everything except OpRangeNotAvailable errors, these are normal
|
# log everything except OpRangeNotAvailable errors, these are normal
|
||||||
if error?
|
if error?
|
||||||
# downgrade OpRangeNotAvailable and "Delete component" errors so they are not sent to sentry
|
# downgrade OpRangeNotAvailable and "Delete component" errors so they are not sent to sentry
|
||||||
logAsWarning = (error instanceof Errors.OpRangeNotAvailableError) || ((typeof error is' string') && error.match(/^Delete component/))
|
logAsWarning = (error instanceof Errors.OpRangeNotAvailableError) || (error instanceof Errors.DeleteMismatchError)
|
||||||
if logAsWarning
|
if logAsWarning
|
||||||
logger.warn err: error, project_id: project_id, doc_id: doc_id, "error processing update"
|
logger.warn err: error, project_id: project_id, doc_id: doc_id, "error processing update"
|
||||||
else
|
else
|
||||||
|
|
|
@ -19,7 +19,15 @@ ProjectStateChangedError = (message) ->
|
||||||
return error
|
return error
|
||||||
ProjectStateChangedError.prototype.__proto__ = Error.prototype
|
ProjectStateChangedError.prototype.__proto__ = Error.prototype
|
||||||
|
|
||||||
|
DeleteMismatchError = (message) ->
|
||||||
|
error = new Error(message)
|
||||||
|
error.name = "DeleteMismatchError"
|
||||||
|
error.__proto__ = DeleteMismatchError.prototype
|
||||||
|
return error
|
||||||
|
DeleteMismatchError.prototype.__proto__ = Error.prototype
|
||||||
|
|
||||||
module.exports = Errors =
|
module.exports = Errors =
|
||||||
NotFoundError: NotFoundError
|
NotFoundError: NotFoundError
|
||||||
OpRangeNotAvailableError: OpRangeNotAvailableError
|
OpRangeNotAvailableError: OpRangeNotAvailableError
|
||||||
ProjectStateChangedError: ProjectStateChangedError
|
ProjectStateChangedError: ProjectStateChangedError
|
||||||
|
DeleteMismatchError: DeleteMismatchError
|
||||||
|
|
|
@ -7,6 +7,8 @@ Keys = require "./UpdateKeys"
|
||||||
util = require "util"
|
util = require "util"
|
||||||
RealTimeRedisManager = require "./RealTimeRedisManager"
|
RealTimeRedisManager = require "./RealTimeRedisManager"
|
||||||
crypto = require "crypto"
|
crypto = require "crypto"
|
||||||
|
metrics = require('./Metrics')
|
||||||
|
Errors = require("./Errors")
|
||||||
|
|
||||||
ShareJsModel:: = {}
|
ShareJsModel:: = {}
|
||||||
util.inherits ShareJsModel, EventEmitter
|
util.inherits ShareJsModel, EventEmitter
|
||||||
|
@ -36,9 +38,15 @@ module.exports = ShareJsUpdateManager =
|
||||||
model.applyOp doc_key, update, (error) ->
|
model.applyOp doc_key, update, (error) ->
|
||||||
if error?
|
if error?
|
||||||
if error == "Op already submitted"
|
if error == "Op already submitted"
|
||||||
|
metrics.inc "sharejs.already-submitted"
|
||||||
logger.warn {project_id, doc_id, update}, "op has already been submitted"
|
logger.warn {project_id, doc_id, update}, "op has already been submitted"
|
||||||
update.dup = true
|
update.dup = true
|
||||||
ShareJsUpdateManager._sendOp(project_id, doc_id, update)
|
ShareJsUpdateManager._sendOp(project_id, doc_id, update)
|
||||||
|
else if /^Delete component/.test(error)
|
||||||
|
metrics.inc "sharejs.delete-mismatch"
|
||||||
|
logger.warn {project_id, doc_id, update, shareJsErr: error}, "sharejs delete does not match"
|
||||||
|
error = new Errors.DeleteMismatchError("Delete component does not match")
|
||||||
|
return callback(error)
|
||||||
else
|
else
|
||||||
return callback(error)
|
return callback(error)
|
||||||
logger.log project_id: project_id, doc_id: doc_id, error: error, "applied update"
|
logger.log project_id: project_id, doc_id: doc_id, error: error, "applied update"
|
||||||
|
|
|
@ -235,7 +235,7 @@ describe "Applying updates to a doc", ->
|
||||||
JSON.parse(message).should.deep.include {
|
JSON.parse(message).should.deep.include {
|
||||||
project_id: @project_id,
|
project_id: @project_id,
|
||||||
doc_id: @doc_id,
|
doc_id: @doc_id,
|
||||||
error:'Delete component \'not the correct content\' does not match deleted text \'one\ntwo\nthree\''
|
error:'Delete component does not match'
|
||||||
}
|
}
|
||||||
|
|
||||||
describe "with enough updates to flush to the track changes api", ->
|
describe "with enough updates to flush to the track changes api", ->
|
||||||
|
|
|
@ -3,19 +3,20 @@ chai = require('chai')
|
||||||
should = chai.should()
|
should = chai.should()
|
||||||
modulePath = "../../../../app/js/DispatchManager.js"
|
modulePath = "../../../../app/js/DispatchManager.js"
|
||||||
SandboxedModule = require('sandboxed-module')
|
SandboxedModule = require('sandboxed-module')
|
||||||
|
Errors = require "../../../../app/js/Errors.js"
|
||||||
|
|
||||||
describe "DispatchManager", ->
|
describe "DispatchManager", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@timeout(3000)
|
@timeout(3000)
|
||||||
@DispatchManager = SandboxedModule.require modulePath, requires:
|
@DispatchManager = SandboxedModule.require modulePath, requires:
|
||||||
"./UpdateManager" : @UpdateManager = {}
|
"./UpdateManager" : @UpdateManager = {}
|
||||||
"logger-sharelatex": @logger = { log: sinon.stub() }
|
"logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub(), warn: sinon.stub() }
|
||||||
"settings-sharelatex": @settings =
|
"settings-sharelatex": @settings =
|
||||||
redis:
|
redis:
|
||||||
realtime: {}
|
realtime: {}
|
||||||
"redis-sharelatex": @redis = {}
|
"redis-sharelatex": @redis = {}
|
||||||
"./RateLimitManager": {}
|
"./RateLimitManager": {}
|
||||||
|
"./Errors": Errors
|
||||||
"./Metrics":
|
"./Metrics":
|
||||||
Timer: ->
|
Timer: ->
|
||||||
done: ->
|
done: ->
|
||||||
|
@ -38,23 +39,51 @@ describe "DispatchManager", ->
|
||||||
@doc_id = "doc-id-123"
|
@doc_id = "doc-id-123"
|
||||||
@doc_key = "#{@project_id}:#{@doc_id}"
|
@doc_key = "#{@project_id}:#{@doc_id}"
|
||||||
@client.blpop = sinon.stub().callsArgWith(2, null, ["pending-updates-list", @doc_key])
|
@client.blpop = sinon.stub().callsArgWith(2, null, ["pending-updates-list", @doc_key])
|
||||||
@UpdateManager.processOutstandingUpdatesWithLock = sinon.stub().callsArg(2)
|
|
||||||
|
describe "in the normal case", ->
|
||||||
@worker._waitForUpdateThenDispatchWorker @callback
|
beforeEach ->
|
||||||
|
@UpdateManager.processOutstandingUpdatesWithLock = sinon.stub().callsArg(2)
|
||||||
it "should call redis with BLPOP", ->
|
@worker._waitForUpdateThenDispatchWorker @callback
|
||||||
@client.blpop
|
|
||||||
.calledWith("pending-updates-list", 0)
|
it "should call redis with BLPOP", ->
|
||||||
.should.equal true
|
@client.blpop
|
||||||
|
.calledWith("pending-updates-list", 0)
|
||||||
it "should call processOutstandingUpdatesWithLock", ->
|
.should.equal true
|
||||||
@UpdateManager.processOutstandingUpdatesWithLock
|
|
||||||
.calledWith(@project_id, @doc_id)
|
it "should call processOutstandingUpdatesWithLock", ->
|
||||||
.should.equal true
|
@UpdateManager.processOutstandingUpdatesWithLock
|
||||||
|
.calledWith(@project_id, @doc_id)
|
||||||
it "should call the callback", ->
|
.should.equal true
|
||||||
@callback.called.should.equal true
|
|
||||||
|
it "should not log any errors", ->
|
||||||
|
@logger.error.called.should.equal false
|
||||||
|
@logger.warn.called.should.equal false
|
||||||
|
|
||||||
|
it "should call the callback", ->
|
||||||
|
@callback.called.should.equal true
|
||||||
|
|
||||||
|
describe "with an error", ->
|
||||||
|
beforeEach ->
|
||||||
|
@UpdateManager.processOutstandingUpdatesWithLock = sinon.stub().callsArgWith(2, new Error("a generic error"))
|
||||||
|
@worker._waitForUpdateThenDispatchWorker @callback
|
||||||
|
|
||||||
|
it "should log an error", ->
|
||||||
|
@logger.error.called.should.equal true
|
||||||
|
|
||||||
|
it "should call the callback", ->
|
||||||
|
@callback.called.should.equal true
|
||||||
|
|
||||||
|
describe "with a 'Delete component' error", ->
|
||||||
|
beforeEach ->
|
||||||
|
@UpdateManager.processOutstandingUpdatesWithLock = sinon.stub().callsArgWith(2, new Errors.DeleteMismatchError())
|
||||||
|
@worker._waitForUpdateThenDispatchWorker @callback
|
||||||
|
|
||||||
|
it "should log a warning", ->
|
||||||
|
@logger.warn.called.should.equal true
|
||||||
|
|
||||||
|
it "should call the callback", ->
|
||||||
|
@callback.called.should.equal true
|
||||||
|
|
||||||
describe "run", ->
|
describe "run", ->
|
||||||
it "should call _waitForUpdateThenDispatchWorker until shutting down", (done) ->
|
it "should call _waitForUpdateThenDispatchWorker until shutting down", (done) ->
|
||||||
callCount = 0
|
callCount = 0
|
||||||
|
|
|
@ -18,6 +18,7 @@ describe "ShareJsUpdateManager", ->
|
||||||
"redis-sharelatex" : createClient: () => @rclient = auth:->
|
"redis-sharelatex" : createClient: () => @rclient = auth:->
|
||||||
"logger-sharelatex": @logger = { log: sinon.stub() }
|
"logger-sharelatex": @logger = { log: sinon.stub() }
|
||||||
"./RealTimeRedisManager": @RealTimeRedisManager = {}
|
"./RealTimeRedisManager": @RealTimeRedisManager = {}
|
||||||
|
"./Metrics": @metrics = { inc: sinon.stub() }
|
||||||
globals:
|
globals:
|
||||||
clearTimeout: @clearTimeout = sinon.stub()
|
clearTimeout: @clearTimeout = sinon.stub()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue