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

core(target-manager): only listen to LH sessions #14385

Merged
merged 14 commits into from
Sep 30, 2022
Merged

Conversation

adamraine
Copy link
Member

@adamraine adamraine commented Sep 13, 2022

This PR upgrades Puppeteer to 18 for two reasons

Upgrading Puppeteer independently of target manager changes increased the likelihood of oopif-request failures (#14398), so I bundled these changes together.


I was not able to reproduce the oopif-requests failure locally. However, I could find unsolicited network responses when I narrowed the focus of my testing to just network manager:

import puppeteer from 'puppeteer';
import {TargetManager} from '../../lighthouse/core/gather/driver/target-manager.js';

const requestedUrls = new Set();
const unsolicitedResponses = [];

const browser = await puppeteer.launch({
  headless: false,
  defaultViewport: puppeteer.devices['Moto G4'].viewport,
  ignoreDefaultArgs: ['--enable-automation'],
  executablePath: process.env.CHROME_PATH,
});
const page = await browser.newPage();
const session = await page.target().createCDPSession();

const targetManager = new TargetManager(session);
await targetManager.enable();
targetManager.on('protocolevent', e => {
  if (e.method === 'Network.responseReceived') {
    const url = e.params.response.url;
    if (!requestedUrls.has(url)) {
      unsolicitedResponses.push(url);
    }
  } else if (e.method === 'Network.requestWillBeSent') {
    requestedUrls.add(e.params.request.url);
  }
});

await page.goto('http://localhost:10200/oopif-requests.html', {
  waitUntil: ['networkidle0'],
});

console.log(JSON.stringify(unsolicitedResponses, null, 2));
console.log('Requested #', requestedUrls.size);

await page.close();
await browser.close();

I believe that the issues were caused by sessions created by Puppeteer being emitted into our session handler. TBH I didn't figure out the exact details for why this was a problem.

However, restricting our session handlers to handle only the sessions that we create seems to have fixed the issue. That is what is being done in this PR. We should run CI a few times as per usual.

See #14385 (comment) for explanation.

@adamraine adamraine requested a review from a team as a code owner September 13, 2022 00:15
@adamraine adamraine requested review from connorjclark and removed request for a team September 13, 2022 00:15
@adamraine
Copy link
Member Author

Hmm seems to have made the problem worse actually

@adamraine
Copy link
Member Author

Looks like the latest puppeteer was necessary for this

@adamraine
Copy link
Member Author

Seems like this has fixed or at least reduced the likelihood of an oopif-requests failure.

However, the Puppeteer upgrade seems to have dramatically increased the likelihood of a lantern-idle-callback-short failure #14271.

I'll keep this open but we should resolve the lantern-idle-callback-short situation before merging.

Copy link
Member

@paulirish paulirish left a comment

Choose a reason for hiding this comment

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

This PR suggests that sessionattached was fired only on the rootConnection.
And it suggests that with the pptr version bump to 17, it's not reliably emitted there, but instead within child connections.

Is that true?

( As we've done a lot to clean up our target management recently, I'd like to be specific and surgical in making any changes. )

@adamraine
Copy link
Member Author

And it suggests that with the pptr version bump to 17, it's not reliably emitted there, but instead within child connections.

It is reliably emitted, but on rootConnection we will emit sessionattached events for any session. This includes sessions automatically created by Puppeteer.

In addition to the sessions automatically created by Puppeteer, there are sessions we create when we call Target.setAutoAttach. These sessions will be emitted on the sessionattached events for the rootConnection as well as sessionattached events for the parent session.

This PR changes things so that we only listen to sessionattached on LH specific sessions so we aren't working with the sessions automatically created by Puppeteer.

@brendankenny
Copy link
Member

However, I could find unsolicited network responses when I narrowed the focus of my testing to just network manager

FWIW unsolicitedResponses is always empty for me, whether on pptr 16 or 17 (10x runs each). Is that example very flaky for you?

@adamraine
Copy link
Member Author

Is that example very flaky for you?

It was somewhat flaky but I don't think I ever saw unsolicitedResponses completely empty.

@brendankenny
Copy link
Member

from some of the discussion from last week:

  • What sessions are being attached that we don't want to listen to?
  • The oopif-requests failures in CI seem to all be from missing requests (from the ones I've seen at least, e.g. this one), but this change is to eliminate unexpected extra requests?
  • What kind of thing are you seeing in unsolicitedResponses? I'm still always getting empty results (being able to repro would also help answer the first question)

@adamraine
Copy link
Member Author

adamraine commented Sep 21, 2022

TBH I didn't figure out the exact details for why this was a problem.

I have a more concrete explanation now.

What sessions are being attached that we don't want to listen to?

Puppeteer automatically creates its own sessions and emits them via connection.on('sessionattached') regardless of what Lighthouse does. These sessions are usable, but Puppeteer controls when Runtime.runIfWaitingForDebugger is called. We want to work with sessions we create instead, that way Puppeteer doesn't prematurely resume the targets.

We are still creating our own sessions, but they are ignored if a Puppeteer created session on the same target has already been handled:

if (this._targetIdToTargets.has(targetId)) return;

BTW this return ^ statement isn't the end of the function because it is wrapped in a try ... finally, so the session is always resumed even though we ignore it for target management:

} finally {
// Resume the target if it was paused, but if it's unnecessary, we don't care about the error.
await newSession.sendCommand('Runtime.runIfWaitingForDebugger').catch(() => {});
}

The oopif-requests failures in CI seem to all be from missing requests (from the ones I've seen at least, e.g. this one), but this change is to eliminate unexpected extra requests?

This change isn't designed to eliminate extra requests. It's to prevent us from using sessions that Puppeteer has already resumed before we call Network.enable.

The missing requests can come from missing Network.requestWillBeSent events which I observed in the DevTools log of CI failure artifacts.

What kind of thing are you seeing in unsolicitedResponses? I'm still always getting empty results (being able to repro would also help answer the first question)

Requests that had a Network.responseReceived event but no Network.requestWillBeSent event. This is a sign that Network.enable was not called in time. This will show up as a missing request in our network requests.

@adamraine
Copy link
Member Author

https://github.com/GoogleChrome/lighthouse/actions/runs/3108583849/jobs/5038074267

Possibly introduced by Puppeteer 18.03 -> 18.05 or something in DT or maybe its just more flakiness.

In any case, this PR alone probably shouldn't close #14271

@adamraine adamraine merged commit bf8df46 into main Sep 30, 2022
@adamraine adamraine deleted the target-manager-restrict branch September 30, 2022 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

oopif-requests flaky on windows
5 participants