-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
Eliminate errors from calling ChromeLauncher.kill() twice #1131
Conversation
The error happened outside the Promise chain and is uncatchable.
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed, please reply here (e.g.
|
I signed it! |
CLAs look good, thanks! |
can you tell us when this exactly happens? |
reproducible when doing
Nobody would ever do exactly this but in some flows this might happen. In my particular case I had set up a Regardless of this corner case though, the existing code has a possibility of throwing an error that can't be caught by any consuming code. In the
The fact that this comment exists means to me that trying to kill a non-running launcher is defined behavior. And the behavior is 'fail silently', which I implemented for the case where you try to kill an already killed launcher. There's also other ways of fixing this:
|
I would go for
Than we can keep everything sync :) |
even if you went the way of the current PR these should really be nulled after closing anyways, so it would be great to go that way |
@wardpeet is there any specific reason you prefer the sync methods over the async ones? The main reason why I changed this code is because I want to be able to handle the errors that might possibly be thrown by |
It's only my personal experience if you don't use async await, promises make your code more complex than using plain sync when it's not necessary. |
* add nulling of properties * make synchronous again
I disagree, but I don't think it's worth starting an argument over. I updated it, can you take another look? |
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 could be good to add a unit test that we avoid this error, but we can do that in a future PR if you'd rather move forward with the scope of this one.
if (this.outFile) { | ||
fs.closeSync(this.outFile); | ||
} | ||
try { |
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'd rather avoid the try/catch since it'll silently eat errors, but is it even necessary? This is the only place that these files are closed, so the conditionals should guard against attempting to delete with already-closed file descriptor.
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.
wrapped the whole function in the promise, instead of only rimraf
@brendankenny Added a test |
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.
a few last style nits
rimraf(this.TMP_PROFILE_DIR, function() { | ||
resolve(); | ||
}); | ||
rimraf(this.TMP_PROFILE_DIR, () => resolve()); |
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.
nit: this can be just rimraf(this.TMP_PROFILE_DIR, () => resolve());
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.
did you mean rimraf(this.TMP_PROFILE_DIR, resolve);
? I chose the former because the return type is Promise<undefined>
and the callback to rimraf
could return with an error.
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.
ah, good point, SGTM as is
|
||
const ChromeLauncher = require('../../chrome-launcher.js').ChromeLauncher; | ||
|
||
/* global describe, it */ |
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.
use /* eslint-env mocha */
instead
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.
That's what I usually use but /* global describe, it */
is all over the code base.
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.
yeah, sorry, that's legacy stuff that's slowly getting changed over as those files are touched :)
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 can replace it everywhere if you want, or would that clutter this PR too much?
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.
yeah, I generally prefer keeping PRs contained and we can have a separate PR for that (and/or change as we go since it's functionally equivalent)
const chromeInstance = new ChromeLauncher(); | ||
chromeInstance.prepare(); | ||
chromeInstance.run(); | ||
return chromeInstance.waitUntilReady() |
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 believe you can do just
const chromeInstance = new ChromeLauncher();
return chromeInstance.run()
.then(() => {
...
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.
Ok, it was like that in manual-chrome-launcher
. Can change there as well?
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.
sounds good
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.
er, I think it's fine as is. I'd rather avoid touching it so we can land this change
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.
chromeInstance.run()
also waits on waitUntilReady()
internally, so it isn't necessary to call chromeInstance.waitUntilReady()
explicitly
.then(() => { | ||
return Promise.all([ | ||
chromeInstance.kill(), | ||
chromeInstance.kill() |
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.
👍
feel free to cancel https://travis-ci.org/GoogleChrome/lighthouse/builds/183750931 to clear up queue |
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
Thanks!
The error happened outside the Promise chain and is uncatchable.