-
Notifications
You must be signed in to change notification settings - Fork 452
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🐛 Unhandled rejection when submitting ops during hard rollback. #692
Conversation
70e8163
to
d6842e4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test, please!
if (this._isInHardRollback) { | ||
var err = new ShareDBError( | ||
ERROR_CODE.ERR_DOC_IN_HARD_ROLLBACK, | ||
'Cannot submit op. Document is performing hard rollback. ' + this.collection + '.' + this.id | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could just move this after the var err = new ShareDBError(ERR_DOC_DOES_NOT_EXIST)
to override this "default" error and then avoid having to duplicate the emit()
machinery
Yes i know want to prepare the test today, just need to fiddle a bit to make it work. Just wanted to push it first, so the @ericyhwang get a chance to look into it before the meeting :) |
a8e8f0c
to
814e814
Compare
After doing the steps: 1. Create a doc with rich text type (or any other non irreversible type) 2. Make op submission fail 3. Now in the hard rollback we do `this._setType(null);` 4. If there is any op comming before the hard rollback `fetch` is finished, we get the error ``` Cannot submit op. Document has not been created. ``` as in the `_submit` we do: ```typescript if (!this.type) { var err = new ShareDBError( ERROR_CODE.ERR_DOC_DOES_NOT_EXIST, 'Cannot submit op. Document has not been created. ' + this.collection + '.' + this.id ); if (callback) return callback(err); return this.emit('error', err); } ``` We definitely do not handle this case properly. Possible solutions: 1. Just throw error whenever that happens, which is easy to implement and it is not really breaking. User would be then able to react on the error or just ignore it. 2. Store copy of cannonical snapshot in the doc itself, so that we do not have to do fetch for hard rollback. More difficult to implement and has a side effect of storing the doc twice in the memory.
814e814
to
6f3869c
Compare
To be honest i think there might be more to this than just my fix as before fetch we do this._setType(null);
this.version = null;
this.inflightOp = null;
this.pendingOps = []; and after fetch is finished if (inflightOp) pendingOps.unshift(inflightOp);
var allOpsHadCallbacks = !!pendingOps.length;
for (var i = 0; i < pendingOps.length; i++) {
allOpsHadCallbacks = util.callEach(pendingOps[i].callbacks, err) && allOpsHadCallbacks;
}
if (err && !allOpsHadCallbacks) doc.emit('error', err);
doc._isInHardRollback = false;
```,
I think it was menat to reject all ops that were added after fetch started. I am not sure just throwing the above error wouldn't break anything. Even though all tests are passing. |
lib/client/doc.js
Outdated
@@ -1077,7 +1088,10 @@ Doc.prototype._hardRollback = function(err) { | |||
inflightOp = null; | |||
} | |||
|
|||
if (!pendingOps.length) return; | |||
if (!pendingOps.length) { | |||
doc._isInHardRollback = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to avoid potential future issues with forgetting to reset _isInHardRollback
on early returns, we could reset to false at the top of this _fetch
callback
0857be5
to
fd67b16
Compare
After doing the steps:
this._setType(null);
fetch
is finished, we get the erroras in the
_submit
we do:We definitely do not handle this case properly. Possible solutions: