Skip to content

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

Merged
merged 20 commits into from
May 18, 2020

Conversation

emadum
Copy link
Contributor

@emadum emadum commented May 8, 2020

Description

Introduced getCursor method to safely provide a change stream cursor
for next/hasNext across recoveries from resumable errors.

NODE-2548

What changed?

  • next and hasNext now use getCursor
  • processError was extracted from processNewChange
  • added withCursor shared test helper

Are there any files to ignore?

@emadum emadum marked this pull request as ready for review May 8, 2020 21:08
@emadum emadum requested review from reggi and mbroadst May 8, 2020 23:01
Copy link
Member

@mbroadst mbroadst left a 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) {
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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));
    });
  });
}

Copy link
Member

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(...);
   });
}

Copy link
Member

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

@emadum emadum removed the request for review from reggi May 11, 2020 19:04
@@ -2850,3 +2858,99 @@ describe('Change Streams', function() {
});
});
});

describe('Change Stream Resume Error Tests', function() {
function withChangeStream(testName, callback) {
Copy link
Member

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.

@emadum emadum requested review from mbroadst and reggi May 14, 2020 22:04
Copy link
Contributor

@reggi reggi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@mbroadst mbroadst left a 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) {
Copy link
Member

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

Copy link
Contributor Author

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?

@emadum emadum merged commit 5ecf18e into 3.5 May 18, 2020
@emadum emadum deleted the NODE-2548/fix-changestream-iterator-resume branch May 18, 2020 13:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants