-
Notifications
You must be signed in to change notification settings - Fork 1.8k
fix(ChangeStream): should resume from errors when iterating #2360
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
Conversation
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.
Nice refactor for processError
! This is looking really great, I've just got some questions and a few suggestions.
@@ -2850,3 +2858,99 @@ describe('Change Streams', function() { | |||
}); | |||
}); | |||
}); | |||
|
|||
describe('Change Stream Resume Error Tests', function() { | |||
function withChangeStream(testName, callback) { |
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.
I think this might be useful as a more generalized helper withCursor
, which we could alias to withChangeStream
if that helps readability at all. Also, I think hiding a call to withClient
in here might not be ideal since its sort of a side effect.
Finally, nitpick but testName
seems to really be like collectionName
?
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.
Waiting on #2362 to see how to best address this.
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.
I didn't ultimately find the withDb
or withCollection
helpers helped very much over there, but cursors are much more like clients, in that they have explicit close
methods that sometimes need to be called.
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.
I added a withCursor
helper; it's a general-purpose wrapper around withClient
. Is this roughly what you had in mind?
function withCursor(getCursor, callback) {
return withClient((client, done) => {
getCursor(client, (err, cursor) => {
if (err) return done(err);
callback(cursor, () => cursor.close(done));
});
});
}
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.
I think of withX
as a means of conveying the lifetime of a resource. So my thought with withCursor
is that it would be like withClient
, but not use withClient
:
function withCursor(cursor, body) {
body(cursor, (err, result) => {
cursor.close(); // always close the cursor, this obviously would need to be async and handle errors etc
callback(...);
});
}
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.
it may not be worth the effort considering we have this.defer
?
const cursor = coll.find();
this.defer(() => cursor.close());
cursor.toArray(...);
could work fine, but you might forget to put the defer in between creating the cursor and iterating it
@@ -2850,3 +2858,99 @@ describe('Change Streams', function() { | |||
}); | |||
}); | |||
}); | |||
|
|||
describe('Change Stream Resume Error Tests', function() { | |||
function withChangeStream(testName, callback) { |
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.
I didn't ultimately find the withDb
or withCollection
helpers helped very much over there, but cursors are much more like clients, in that they have explicit close
methods that sometimes need to be called.
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.
LGTM
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.
LGTM!
* @param {(cursor: Object, done: Function) => void} body test body | ||
* @param {Function} done called after cleanup | ||
*/ | ||
function withCursor(cursor, body, done) { |
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.
Just a thought, and not one I wanted to block this review on:
This helper doesn't account for tests which return a promise, which is a similar discussion to ones we've had previously in withClient
and friends. I wonder if what we eventually want is some helper like withCloseable
which is internally used by withClient
, withMonitoredClient
, withCursor
and maybe even something like withSession
(though this is an existing helper in the public API). Food for thought
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.
Agreed it would be nice for withMonitoredClient
and withCursor
to support promises as well as callbacks, the way withClient
does. I think refactoring to use withCloseable
would be a nice reduction of duplicated logic but I don't see how it would add much utility. Perhaps it's something we can work into a future PR where we're trying to write promise-based tests that need monitored clients or cursors?
Description
Introduced
getCursor
method to safely provide a change stream cursorfor
next
/hasNext
across recoveries from resumable errors.NODE-2548
What changed?
next
andhasNext
now usegetCursor
processError
was extracted fromprocessNewChange
withCursor
shared test helperAre there any files to ignore?