-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
track enabled debugger domains for safe simultaneous use #1474
Conversation
There are still a few gotchas that we're living with that this doesn't solve. A big one is for domains where we listen to an event and then enable the domain. We rely on the protocol to have buffered all previous events and to replay them all once the domain is enabled. We use this in quite a few places ( This also doesn't check who is doing the enabling and disabling, so in theory gatherer2 could close the domain gatherer1 just opened and still cause an interaction bug. Tokens for enable/disable didn't really seem worth it, but I'm open to it. I'm also thinking in a followup PR we could add a "clear domain state" step between passes in gatherRunner, with a suitable |
@@ -100,7 +100,8 @@ class Connection { | |||
// handleRawError returns or throws synchronously; wrap to put into promise chain. | |||
return callback.resolve(Promise.resolve().then(_ => { | |||
if (object.error) { | |||
return this.handleRawError(object.error, callback.method); | |||
log.formatProtocol('method <= browser ERR', {method: callback.method}, 'error'); | |||
throw new Error(`Protocol error (${callback.method}): ${object.error.message}`); |
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.
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.
Am I right that some domains throw and error if you call disable twice and some do not? Might be worth bringing up with the DT times. That seems inconsistent at best.
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.
definitely inconsistent. From #861 is this cs link, currently showing only DOM
complains if you disable when already disabled: https://cs.chromium.org/search/?q=if.*!enabled+file:%5Esrc/third_party/WebKit/Source/core/inspector/+case:yes&sq=package:chromium&type=cs
@patrickhulce @paulirish if they want to pursue a debugger protocol bug :)
// Enable Page domain to wait for Page.loadEventFired | ||
.then(_ => this.sendCommand('Page.enable')) | ||
// Check any domains that could interfere with or add overhead to the trace. | ||
if (this.domainEnabled('Debugger')) { |
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 moves these to just being a log error message. Disabling these domains after beforePass
has executed if a trace is being taken means that e.g. if someone adds a DBW gatherer that needs a trace then any DBW gatherer that enabled Debugger
, CSS
, or DOM
in beforePass
will be broken, possibly fairly subtly. Better to warn on these...or even throw 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.
the log error message will propagate all the way into the report right? If it were an error, the DBW audit/gatherer would surface a -1 in the report?
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.
If we're no longer disabling these before a trace, won't that change perf results?
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.
If we're no longer disabling these before a trace, won't that change perf results?
In the current config these domains aren't enabled when we take a trace, so there's no change currently. If we add a gatherer that does enable one of these domains before a trace, though, it could cause a difference, which is why I kept a warning message. Maybe that's not enough, though.
the log error message will propagate all the way into the report right? If it were an error, the DBW audit/gatherer would surface a -1 in the report?
log.error
only logs it in red to the CLI/console, which hopefully someone catches :)
The problem with the approach on master is that it introduces errors but in the opposite way: it undercuts any gatherers that may unknowingly be running in the same pass as a trace being taken. The result may be subtle and not an error. e.g. a gather is listening for a CSS
event that never comes because driver has disabled the CSS
domain out from under it, but the lack of an event may just mean whatever it was gathering didn't happen on this particular page.
Maybe as suggested we do want to assert the domains are disabled and throw if they aren't, with a nice error message saying that the current config has gatherers interfering with a trace
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'm specifically thinking of CRX users who wouldn't see cli/console logs. But if the error surfaces up at the end (or as a failure during the CRX run), then it's all good.
assert the domains are disabled and throw if they aren't
Yea. That would be a good way for use to verify no one tries do so anything crazy during a trace in the future.
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.
turned into thrown errors
@@ -530,9 +588,6 @@ class Driver { | |||
|
|||
_readTraceFromStream(streamHandle) { | |||
return new Promise((resolve, reject) => { | |||
// COMPAT: We've found `result` not retaining its value in this scenario when it's |
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.
obsolete comment
// return driver.sendCommand('CSS.disable') | ||
// .then(_ => driver.sendCommand('DOM.disable')) | ||
// .then(_ => resolve(styleHeaders)); | ||
|
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.
commented out in #1421. Verified that bringing this back without tracking domains failed the DBW smoke test (in the unused-css-rules
audit), but with this change it now passes correctly
* @param {string} domain | ||
* @return {boolean} | ||
*/ | ||
domainEnabled(domain) { |
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 curious here, what are your thoughts in general on isX
prefixing for all boolean values/functions?
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 would be in favor of us "standardizing" on a convention. Been wrestling with this myself.
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.
sometimes I find it redundant but in this case I think it helps clarity. 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.
interesting route! what do you think about having gatherers declare the domains they use as an approach to solve both this and the still lingering buffered events issue?
* @return {boolean} | ||
* @private | ||
*/ | ||
_checkDomainToggle(domain, action) { |
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.
maybe something slightly more explicit for the name like _shouldSendDomainCommand
or _shouldToggleDomain
?
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
It seems the main problem with this approach is how you define a failure case. e.g. it's fine for the Taking a different tack, there's not really a way to limit the domain declarations to gatherers who need to say "I'm going to enable this domain and it better be disabled when I enable it", because some other gatherer might need that domain but not need the events from it, so doesn't need that guarantee. It really seems like manually checking that a domain is disabled when you need that behavior, and throwing an unrecoverable error otherwise, is the best way to catch this, but also the least automatically testable. I guess we could wrap that up for folks, |
I like that. In cases where they care the gatherer can assert and flip on manually, but in cases where they don't need it to be disabled at start it can be just declared as needed. |
* @private | ||
*/ | ||
_checkDomainToggle(domain, action) { | ||
const enable = action === 'enable'; |
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.
should action
just be a boolean instead of passing string around?
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's slightly more awkward but probably better. Done.
* @param {string} domain | ||
* @return {boolean} | ||
*/ | ||
domainEnabled(domain) { |
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 would be in favor of us "standardizing" on a convention. Been wrestling with this myself.
// Enable Page domain to wait for Page.loadEventFired | ||
.then(_ => this.sendCommand('Page.enable')) | ||
// Check any domains that could interfere with or add overhead to the trace. | ||
if (this.domainEnabled('Debugger')) { |
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.
the log error message will propagate all the way into the report right? If it were an error, the DBW audit/gatherer would surface a -1 in the report?
// Enable Page domain to wait for Page.loadEventFired | ||
.then(_ => this.sendCommand('Page.enable')) | ||
// Check any domains that could interfere with or add overhead to the trace. | ||
if (this.domainEnabled('Debugger')) { |
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.
If we're no longer disabling these before a trace, won't that change perf results?
updated. PTAL |
gatherRunner, driver, and gatherers enable and disable domains at will, and we currently have no system for tracking the state of them so that they don't interfere with each other. This has happened a few times in the past and it's difficult to track down why e.g. an event never fires because someone else disabled the domain you were listening to. Most recently this came up in #1421 where the
styles
andcss-usage
gatherers interfere when cleaning up after themselves.This PR tracks
enable
anddisable
commands sent through the driver, eliminates redundant calls and prevents disabling by one user of the domain if others have also enabled it but have not yet disabled it.The second commit is removing some of the places I've remembered us guarding against ourselves which is less necessary after this change.