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

fix: memory leak caused by storing base64 encoded files recieved by CDP Network.requestWillBeSent #22460

Merged

Conversation

DJSdev
Copy link
Contributor

@DJSdev DJSdev commented Jun 22, 2022

User facing changelog

Fixed a memory leak in Chromium-based browsers caused by storing data: url containing base64 encoded files unnecessarily. Fixes #17853

Additional details

Summary

There is a memory leak in the CdpAutomation class that causes Cypress to store data urls as requests in the pendingBrowserPreRequests array.

Background

After updating Cypress to any version higher than 8.2, my e2e suite crashes with the following error after about an hour:

8672:0000371000344000]  3709798 ms: Mark-sweep 1952.5 (2070.7) -> 1946.9 (2071.4) MB, 450.0 / 0.0 ms  (average mu = 0.789, current mu = 0.668) task; scavenge might not succeed
[8672:0000371000344000]  3711538 ms: Mark-sweep 1953.7 (2071.4) -> 1947.8 (2072.4) MB, 350.9 / 0.0 ms  (average mu = 0.793, current mu = 0.798) task; scavenge might not succeed

<--- JS stacktrace --->

[8672:0622/112740.931:ERROR:node_bindings.cc(143)] Fatal error in V8: Reached heap limit Allocation failed - JavaScript heap out of memory

While the tests run, I inspected task manager and I noticed the Cypress server process growing in size until the machine's memory is exhausted causes this issue.

Investigation

I started off by adding code to Cypress to have it dump it's heap memory every 90 seconds.

After 3 minutes of tests, you can see a big difference in the heap sizes between the Cypress 8.2 (first entry) and Cypress 8.1 (second entry)
image

After inspecting the heap memory in the DevTools console I discovered that Cypress is storing hundreds/thousands of copies of a font file.

image

This is a font-file used by my application and it's referenced like so:

image

I discovered in Chrome, when a CSS style sheet uses the url() function in the src field with a base64 encoded file (a data: url), it still triggers Chrome to "send" a network request even though it's not actually going to send one.

image

Cypress subscribes to the Network.requestWillBeSent event in CDP. When Chrome goes to 'fetch' the base64 encoded file, it sends a requestWillBeSent event to Cypress which stores the url (literally a whole file) in the pendingBrowserPreRequests array. Every time the page is loaded with the CSS, a request is sent adding to the buffer until Cypress eventually crashes.

Solution

The solution I went with is very basic. Simply filtering out data: urls from from the Network.requestWillBeSent event handling logic should clear it up.

Another thought was to have logic clear out stale entries from the array, but that's a lot of work for URLs that shouldn't be stored to begin with.

Steps to test

I can generate a test repo that reproduces this issue if anyone requests it.

I tested this with on version 8.2 and 10.2 and verified the issue existed on both versions. (Currently, my team is on 8.0 where this issue doesn't happen. This issue has stopped us from upgrading for a very long time).

I verified after implementing this fix on 10.2, the memory leak no longer happens and data urls are no longer stored in the pendingBrowserPreRequests array.

How has the user experience changed?

Nothing has changed!

PR Tasks

  • Have tests been added/updated?
  • Has the original issue (or this PR, if no issue exists) been tagged with a release in ZenHub? (user-facing changes only)
  • [na] Has a PR for user-facing changes been opened in cypress-documentation?
  • [na] Have API changes been updated in the type definitions?

@DJSdev DJSdev requested a review from a team as a code owner June 22, 2022 19:34
@DJSdev DJSdev requested review from chrisbreiding and removed request for a team June 22, 2022 19:34
@cypress-bot
Copy link
Contributor

cypress-bot bot commented Jun 22, 2022

Thanks for taking the time to open a PR!

@CLAassistant
Copy link

CLAassistant commented Jun 22, 2022

CLA assistant check
All committers have signed the CLA.

@mjhenkes
Copy link
Member

@DJSdev, Thanks so much for this PR. Would it be possible to get a test written for it?

@DJSdev
Copy link
Contributor Author

DJSdev commented Jun 22, 2022

I'll do my best to get a test written for it. It's in a weird place.

@BlueWinds
Copy link
Contributor

I'll do my best to get a test written for it. It's in a weird place.

packages/server/test/unit/browsers/cdp_automation_spec.ts has the existing tests for our CDP integration, and has the helper sendDebuggerCommand which ought to make it easy to send a mocked up Network.requestWillBeSent.

I'd be fine with a test that just emits a Network.requestWillBeSentevent and verifies that onBrowserPreRequest isn't called when it's with a data url.

DJSdev and others added 2 commits June 22, 2022 16:23
grammar :)

Co-authored-by: Sam Tsai <samtsai@gmail.com>
grammar :)

Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
@DJSdev
Copy link
Contributor Author

DJSdev commented Jun 23, 2022

Unit tests have been added. I added some bonus tests around onNetworkRequestWillBeSent and onResponseReceived since there wasn't any around these two functions.

existing tests for our CDP integration, and has the helper sendDebuggerCommand which ought to make it easy to send a mocked up Network.requestWillBeSent.

I wasn't exactly sure how the sendDebuggerCommand worked in regards to these tests. Hopefully triggering the events with the stubbed onFn() will suffice. Looking forward to feedback :)

Copy link
Contributor

@flotwig flotwig left a comment

Choose a reason for hiding this comment

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

Nice!

@BlueWinds
Copy link
Contributor

We have been having some flake problems with our automated test suite recently, which we're working on addressing in several other PRs. Given that the currently failing tests were known to be flaky before this branch, I'm going to exercise my judgement and merge this without waiting for a completely green build.

@BlueWinds BlueWinds merged commit 75a5daf into cypress-io:develop Jun 23, 2022
@Chili82
Copy link

Chili82 commented Jun 23, 2022

Is this fix available on 10.2.0 version?

@vaibhavganatra
Copy link

@Chili82 No. 10.2 was released 2 days ago and this PR got approved just today.

@DJSdev DJSdev deleted the fix/memory-leak-in-cdp-automation branch June 23, 2022 17:12
@Chili82
Copy link

Chili82 commented Jun 23, 2022

Ok, thanks. I guess it will be in the next release.

@BlueWinds
Copy link
Contributor

We're hoping to get 10.2.1 out tomorrow, but it's not ready quite yet.

@Chili82
Copy link

Chili82 commented Jun 23, 2022

Thank you!

@SadiqRahim
Copy link

SadiqRahim commented Jun 23, 2022

Does this fix also resolves the issue where it closes the test before it kick start with the error "The Test Runner unexpectedly exited via a close event with signal SIGILL"?

@BlueWinds
Copy link
Contributor

Doesn't sound related to this fix or the linked issue.

tgriesser added a commit that referenced this pull request Jun 24, 2022
…esser/CLOUD-577-spec-list-display-latest-runs-batching

* muaz/CLOUD-577-spec-list-display-latest-runs:
  fix: Update "Request Access" button state after requesting access (ACI) (#22499)
  feat: Support "Queued" latest run status (#22497)
  fix: remove ctx.cloud.reset in tests, handle infinite loop in stale results (#22483)
  chore: add reporter webpack to gulp watch script (#22386)
  fix: Increase timeout for npm-webpack-dev-server tests (#22489)
  fix: Time out unmatched prerequests in proxy to avoid leaking memory (#22462)
  fix: Sort results in findCrossOriginLogs test helper to deterministic (#22481)
  fix: memory leak caused by storing base64 encoded files recieved by CDP `Network.requestWillBeSent` (#22460)
  fix: Improve cross-origin cookie handling (#22320)
  feat: Add button to clear value from search fields (#22202)
  chore: Add test to verify settings panels are collapsed by default (#22382)
  fix: process_profiler follow up work for v10 (#22363)
  chore: Update Chrome (stable) to 103.0.5060.53 (#22441)
  refactor: use design system windicss config (#21503)
  chore: update readme logo (#22433)
  chore: Update Chrome (beta) to 103.0.5060.53 (#22351)
  chore: updating version (#22432)
  Trigger Build
@cypress-bot
Copy link
Contributor

cypress-bot bot commented Jun 28, 2022

Released in 10.3.0.

This comment thread has been locked. If you are still experiencing this issue after upgrading to
Cypress v10.3.0, please open a new issue.

@cypress-bot cypress-bot bot locked as resolved and limited conversation to collaborators Jun 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tests causing CI agents to run out of memory on cypress 8.2 & above
10 participants