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: retry on EMFILE always, lint sync FS calls #22175

Merged
merged 18 commits into from Jun 16, 2022
Merged

Conversation

flotwig
Copy link
Contributor

@flotwig flotwig commented Jun 7, 2022

User facing changelog

  • Fixed an issue where Cypress would crash with an EMFILE error if the process ran into the file descriptor limit. Cypress will now retry file reads using graceful-fs.

Additional details

  • Applies graceful-fs to fs on startup+nextTick to block EMFILE errors - previously, only fs-extra had graceful-fs protections
  • Adds warnings for sync FS method usage in the server when not in production
  • Adds lint rules for sync FS method usage with ignores for scripts, tests, and non-server code
    • The no-restricted-syntax rule is crazy versatile, you can write arbitrary AST queries to lint using esquery syntax.
  • Updates trivial-to-fix places where we use sync FS methods to use async FS methods
  • Adds eslint-ignores in areas where it doesn't matter (debug code, etc...)
  • Adds TODOs and eslint-ignores where we need to do further work to remove sync FS calls

Steps to test

How has the user experience 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?

@cypress-bot
Copy link
Contributor

cypress-bot bot commented Jun 7, 2022

Thanks for taking the time to open a PR!

@flotwig flotwig changed the title fix: use graceful-fs always, lint and warn in development on sync FS calls fix: use graceful-fs always, lint sync FS calls Jun 7, 2022
@cypress
Copy link

cypress bot commented Jun 7, 2022



Test summary

4874 0 61 0Flakiness 1


Run details

Project cypress
Status Passed
Commit 9321032
Started Jun 16, 2022 1:26 AM
Ended Jun 16, 2022 1:40 AM
Duration 13:46 💡
OS Linux Debian - 10.11
Browser Firefox 98

View run in Cypress Dashboard ➡️


Flakiness

cypress/e2e/e2e/origin/commands/assertions.cy.ts Flakiness
1 cy.origin assertions > #consoleProps > .should() and .and()

This comment has been generated by cypress-bot as a result of this project's GitHub integration settings. You can manage this integration in this project's settings in the Cypress Dashboard

@flotwig flotwig changed the title fix: use graceful-fs always, lint sync FS calls fix: retry on EMFILE always, lint sync FS calls Jun 7, 2022
@flotwig flotwig marked this pull request as ready for review June 8, 2022 15:00
@flotwig flotwig requested review from a team and tgriesser as code owners June 8, 2022 15:00
@flotwig flotwig requested review from jennifer-shehane and MuazOthman and removed request for a team and jennifer-shehane June 8, 2022 15:00
@@ -563,16 +565,11 @@ describe('_makeSpecWatcher', () => {

specWatcher.on('add', (filePath) => allFiles.add(filePath))
specWatcher.on('change', (filePath) => allFiles.add(filePath))
specWatcher.on('unlink', (filePath) => allFiles.delete(filePath))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tgriesser I didn't think we'd be seeing this test so soon again :P I had to modify this test to pass after making so much stuff async, and this line was missing. I think the test is still testing what it's supposed to, can you verify?

Copy link
Contributor

@lmiller1990 lmiller1990 left a comment

Choose a reason for hiding this comment

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

One comment/question around extending this to npm, the rest looks like pretty simple migrations from sync->async. 👏

Also windows is passing on this PR - did you re-run it, or did these changes reduce some flake?

@@ -55,6 +74,16 @@ module.exports = {
message: 'os.userInfo() will throw when there is not an `/etc/passwd` entry for the current user (like when running with --user 12345 in Docker). Do not use it unless you catch any potential errors.',
},
],
'no-restricted-syntax': [
Copy link
Contributor

Choose a reason for hiding this comment

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

Wow, hope we don't need to edit this in the near future, did not realize you could do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah. I pasted a URL there that helps you debug esquery, but even still this took me a bit to figure out.

@@ -38,6 +38,8 @@ export const Cypress = (
const indexHtmlFile = options.cypressConfig.indexHtmlFile

let specsPathsSet = getSpecsPathsSet(specs)
// TODO: use async fs methods here
// eslint-disable-next-line no-restricted-syntax
let loader = fs.readFileSync(INIT_FILEPATH, 'utf8')
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this "do not use sync FS calls" also need to be applied in npm, or just things we know are shipping in the binary (and never published separately on npm). It's possible a user is consuming these outside of Cypress (however unlikely) and they may not have access to wrapped fs module with async extensions.

Seems safest to either us things we know exist in the Node.js standard lib, or have these depend on fs-extra, or use fs.promises (didn't know about this!) to making async versions of the functions we need in each npm module.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd use fs.promises here if I was gonna change this. I started to, but then stopped because it actually requires a user-facing (I think?) type change to make this function async.

Since this is most likely to run in the plugins process, it should be fine to just use fs.promises, since we already run gracefulFs.gracefulify(fs) in the child process:

Copy link
Contributor

Choose a reason for hiding this comment

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

Not too sure this would require a user facing change (this function is internal to the Vite dev server) but sure, happy to leave it like this for now. If we do change it fs.promises seems good.

@flotwig
Copy link
Contributor Author

flotwig commented Jun 9, 2022

Also windows is passing on this PR - did you re-run it, or did these changes reduce some flake?

I think I just got lucky.

@flotwig flotwig requested a review from lmiller1990 June 9, 2022 13:44
Copy link
Contributor

@lmiller1990 lmiller1990 left a comment

Choose a reason for hiding this comment

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

Seems fine, got an answer on my one question.

@tbiethman tbiethman self-requested a review June 15, 2022 15:45
Copy link
Contributor

@tbiethman tbiethman left a comment

Choose a reason for hiding this comment

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

Changes are thorough 👍 I ran a few smoke tests locally and everything is working good. Also added a few sync calls to test the new eslint rule, that is very cool.

Should we log issues for the few remaining TODOs or will we just keep #22028 open for that work?

@flotwig
Copy link
Contributor Author

flotwig commented Jun 15, 2022

@tbiethman I'll update #22028, I think it can encompass the remaining work on this (warn on all sync usage on a monkey-patch level, remove all sync usage)

@lmiller1990 lmiller1990 merged commit d01932b into develop Jun 16, 2022
@lmiller1990 lmiller1990 deleted the block-fs-sync branch June 16, 2022 04:35
BeijiYang pushed a commit to BeijiYang/cypress that referenced this pull request Jun 23, 2022
* fix: use graceful-fs always, warn in development on sync calls

* skip prop linting in some dirs

* eslint rules

* use AST-based lint rule instead

* comment

* ignore existsSync

* run without nextTick

* remove dev warning code

* fix order

* register TS first

* fix tests

* fix test

* cover new call site

* fix new test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

EMFILE eventually crashes cypress open on Linux
3 participants