Skip to content
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

chore: opinionated clean up of once callbacks #180

Merged
merged 3 commits into from
Jul 11, 2018
Merged

Conversation

DonutEspresso
Copy link
Member

@DonutEspresso DonutEspresso commented Jul 11, 2018

As part of #179 I discovered once was being used to enable sloppy behavior of the request lifecycle management. This PR converts all once wrappers of callbacks into once.strict to ensure proper, valid behavior. This will make further improvements more straightforward.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
@coveralls
Copy link

coveralls commented Jul 11, 2018

Coverage Status

Coverage increased (+0.2%) to 87.717% when pulling d86d3bb on once-err into d2817aa on master.

Copy link
Contributor

@misterdjules misterdjules left a comment

Choose a reason for hiding this comment

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

Left a few questions!

@@ -16,7 +16,7 @@ var util = require('util');
var assert = require('assert-plus');
var backoff = require('backoff');
var mime = require('mime');
var once = require('once');
var once = require('once').strict;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I think I'd find it more obvious what behavior is used by each "onced" callback if each was explicitly created with once.strict below instead of once. Reviewing this PR I got confused: I did not understand what had changed since the call sites were using once: I thought they were still using the non-strict versions.

This is highly subjective though, I'm fine if you prefer this style!

@@ -407,6 +385,9 @@ function rawRequest(opts, cb) {
socket.setKeepAlive(true);
}

// eagerly return here with the request. it's still very possible
// for the request to timeout at this point. if that happens, a
// RequestTimeoutError will be emitted as part of the result event.
cb(null, req);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a specific reason why we call cb here instead of in the proto.request callback? Without being familiar with restify client's implementation, I would think the main difference would be that by calling cb here it's called when the connection to the peer is established, but possibly before the first part of the HTTP response was received, whereas by calling it from proto.request's callback, it'd be called only after the first part of the HTTP response was received.

Is that distinction useful? If not, would that allow us to refactor the code in a way that doesn't require us to still write some error prone code to avoid calling cb more than once?

Copy link
Member Author

Choose a reason for hiding this comment

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

You're spot on, I believe the HttpClient works by having "two" areas for error propagation:

httpclient.get('/foo', function(err, req) {
   // err can be DNSTimeout or ConnectTimeout, in which case the 'result' event is never fired
  req.on('result', function(err, res) {
    // err can be RequestTimeout or http level err
  });
});

I'm not sure if the distinction is useful TBH, and it requires consumers to have to check for errors in two places.

emitAfter(req, null, err);
});
req._forcedAbortErr = err;
req.abort();
Copy link
Contributor

Choose a reason for hiding this comment

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

nit/thinking out loud: do we want to assert on req here since it seems we rely on it being a request object? I'm thinking about it more from a code documentation perspective.

cb(err, req);
emitResult(err, req, null);
emitAfter(req, null, err);
req._forcedAbortErr = err;
Copy link
Contributor

Choose a reason for hiding this comment

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

General question: what about using a symbol here to avoid stomping on consumer's properties?

Copy link
Member Author

Choose a reason for hiding this comment

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

@hekike and I were chatting about this the other day - we'd like to add an "engines" field into package.json so we can begin to safely use ES6 stuff, but that'd be reserved for a breaking change. This isn't ideal, but it would keep us from breaking any existing contracts.

Copy link
Contributor

Choose a reason for hiding this comment

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

Absolutely, that makes sense, so this looks good to me!

Copy link
Contributor

@misterdjules misterdjules left a comment

Choose a reason for hiding this comment

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

Thank you! 💯

@DonutEspresso DonutEspresso merged commit 3d9b330 into master Jul 11, 2018
@DonutEspresso DonutEspresso deleted the once-err branch July 11, 2018 21:13
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.

None yet

3 participants