-
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
core: throw fatally on page hang #6497
Conversation
Yes, it just goes on and on my friends. | ||
Some people started computing it, not knowing what it was. | ||
And they'll continue computing it forever just because, | ||
This is the function that never end. |
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.
🤣🤣 nicely 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.
(never ends
:)
@@ -0,0 +1,19 @@ | |||
/** | |||
* @license Copyright 2017 Google Inc. All Rights Reserved. |
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.
2018
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.
done
@@ -0,0 +1,16 @@ | |||
<html> |
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.
license
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.
done
'use strict'; | ||
|
||
/** | ||
* Expected Lighthouse audit values for sites with various errors. |
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.
🎉
@@ -98,10 +99,12 @@ function runLighthouse(url, configPath, isDebug) { | |||
console.error(`STDERR: ${runResults.stderr}`); | |||
} | |||
|
|||
const lhr = fs.readFileSync(outputPath, 'utf8'); | |||
const lhr = runResults.status === PAGE_HUNG_EXIT_CODE ? |
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.
since we don't really do anything else with it below (e.g. no path to debug output), could this be just an early return of the PAGE_HUNG LHR?
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 good point, done!
lighthouse-core/gather/driver.js
Outdated
this._nextProtocolTimeout = DEFAULT_PROTOCOL_TIMEOUT; | ||
const timeout = typeof this._nextProtocolTimeout === 'undefined' ? | ||
DEFAULT_PROTOCOL_TIMEOUT : this._nextProtocolTimeout; | ||
this._nextProtocolTimeout = undefined; |
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.
hmm, I don't follow what this is doing. It seems the default state goes to undefined
, which now gets interpreted as "use the default", but why was that needed for an extra signal?
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.
removed it all 👍
re: alternatives, I personally vote for what's here and then ramping up in the future if we think we can get away with them |
This is the function that never ends | ||
Yes, it just goes on and on my friends. | ||
Some people started computing it, not knowing what it was. | ||
And they'll continue computing it forever just because, |
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.
🤣
@@ -0,0 +1,19 @@ | |||
/** | |||
* @license Copyright 2017 Google Inc. All Rights Reserved. |
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.
its like finding a pokemon! got 'em!
|
||
if (await this.isPageHung()) { | ||
log.warn('Driver', 'Page appears to be hung, killing JavaScript...'); | ||
await this.sendCommand('Runtime.terminateExecution'); |
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 we should also run setScriptDisabled({disabled: true})
at this point.
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.
done
lighthouse-core/gather/driver.js
Outdated
async isPageHung() { | ||
try { | ||
this.setNextProtocolTimeout(5000); | ||
await this.evaluateAsync('"ping"'); |
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.
to simplify we could do a pure sendCommand('Runtime.evalute')
here. we don't really need all that promise wrapping stuff with something so simple.
but i guess it also means we could probably avoid some of the nextTimeout juggling we have since _evaluateInContext
has its own timeout.
double bonus?! :)
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.
SG!
lighthouse-core/gather/driver.js
Outdated
*/ | ||
async isPageHung() { | ||
try { | ||
this.setNextProtocolTimeout(5000); |
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.
5s feels generous. why not 1s
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.
well for turning a run fatal it seemed like we wanted to be pretty sure it's hung and not just hitting a long task during a slow page load, but if you think 1s is enough and 45s pages be damned, I'm on board :)
@@ -749,7 +773,7 @@ class Driver { | |||
loadPromise, | |||
maxTimeoutPromise, | |||
]); | |||
cleanupFn(); | |||
await cleanupFn(); |
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.
now necessary since we have the awaits inside of maxTimeoutPromise, right?
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.
well the awaits are inside the function that it returns too, so we want to wait to find out if the page is hung before moving on
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.
order of execution is
- wait for earlier of
load + quiet
andmaxWaitForLoad
- If we reached
maxWaitForLoad
then check if we're hung
we don't want to be doing our killing and hang check while we're trying to see if the page is quiet.
lighthouse-core/lib/lh-error.js
Outdated
/* Used when the page stopped responding and did not finish loading. */ | ||
PAGE_HUNG: { | ||
code: 'PAGE_HUNG', | ||
message: strings.pageLoadFailed, |
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.
can we do a new string?
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.
sure, the one I have is largely the same as pageLoadFailed
though, so if you have particular hopes of what you want to convey, input welcome :)
@@ -148,6 +148,12 @@ const ERRORS = { | |||
message: strings.pageLoadFailedInsecure, | |||
lhrRuntimeError: true, | |||
}, | |||
/* Used when the page stopped responding and did not finish loading. */ | |||
PAGE_HUNG: { |
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.
this'll need to go into the proto. :)
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.
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.
yes I think we should do this.
I will point out, I think it's possible for the hang to happen during mid-gathering, in which case we wouldn't catch this.
After landing, I think next step is to drop protocol timeout to 10-ish seconds. And then run isPageHung() between gatherers. Unfortch, this overkill is only necessary because of LR, but... yah.
@patrickhulce some of the smokehouse tests are broke. can you take a look |
sneaky, it was an extra empty object definition in the smoketests |
Summary
I've spent way too much time waffling back and forth on how to handle this, so I thought I'd just put it up for discussion. This PR throws a fatal error if, after our maxWaitForLoad is reached, the page doesn't seem to respond.
Right now this basically gets us earlier exit than trying to do all the gathering and not much else. I agree with @brendankenny that it's a bit dangerous to try to kill JavaScript and continue. If we do anything else I think it might be alternative 1, but still feels risky.
Alternatives: