Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0d8cf63

Browse files
nzakasfasttime
andauthored
fix: EMFILE errors (#18313)
* fix: EMFILE errorsfixes#18301* Move catch handler* Add intentional EMFILE failure* Use actual limit on Linux systems in test* Adjust emfile test limit* Fix linting error* Fix test for MacOS* Up MacOS limit in test* Move tmp file output directory* Update .gitignoreCo-authored-by: Francesco Trotta <github@fasttime.org>---------Co-authored-by: Francesco Trotta <github@fasttime.org>
1 parente1ac0b5 commit0d8cf63

File tree

5 files changed

+125
-4
lines changed

5 files changed

+125
-4
lines changed

‎.github/workflows/ci.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ jobs:
6565
run:node Makefile mocha
6666
-name:Fuzz Test
6767
run:node Makefile fuzz
68+
-name:Test EMFILE Handling
69+
run:npm run test:emfile
6870

6971
test_on_browser:
7072
name:Browser Test

‎lib/eslint/eslint.js‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const {
4242
const{ pathToFileURL}=require("url");
4343
const{ FlatConfigArray}=require("../config/flat-config-array");
4444
constLintResultCache=require("../cli-engine/lint-result-cache");
45+
const{ Retrier}=require("@humanwhocodes/retry");
4546

4647
/*
4748
* This is necessary to allow overwriting writeFile for testing purposes.
@@ -851,6 +852,8 @@ class ESLint {
851852
errorOnUnmatchedPattern
852853
});
853854
constcontroller=newAbortController();
855+
constretryCodes=newSet(["ENFILE","EMFILE"]);
856+
constretrier=newRetrier(error=>retryCodes.has(error.code));
854857

855858
debug(`${filePaths.length} files found in:${Date.now()-startTime}ms`);
856859

@@ -919,7 +922,7 @@ class ESLint {
919922
fixer=message=>shouldMessageBeFixed(message,config,fixTypesSet)&&originalFix(message);
920923
}
921924

922-
returnfs.readFile(filePath,{encoding:"utf8",signal:controller.signal})
925+
returnretrier.retry(()=>fs.readFile(filePath,{encoding:"utf8",signal:controller.signal})
923926
.then(text=>{
924927

925928
// fail immediately if an error occurred in another file
@@ -949,11 +952,11 @@ class ESLint {
949952
}
950953

951954
returnresult;
952-
}).catch(error=>{
955+
}))
956+
.catch(error=>{
953957
controller.abort(error);
954958
throwerror;
955959
});
956-
957960
})
958961
);
959962

‎package.json‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
"test:browser":"node Makefile.js wdio",
3434
"test:cli":"mocha",
3535
"test:fuzz":"node Makefile.js fuzz",
36-
"test:performance":"node Makefile.js perf"
36+
"test:performance":"node Makefile.js perf",
37+
"test:emfile":"node tools/check-emfile-handling.js"
3738
},
3839
"gitHooks": {
3940
"pre-commit":"lint-staged"
@@ -71,6 +72,7 @@
7172
"@eslint/js":"9.0.0",
7273
"@humanwhocodes/config-array":"^0.12.3",
7374
"@humanwhocodes/module-importer":"^1.0.1",
75+
"@humanwhocodes/retry":"^0.2.3",
7476
"@nodelib/fs.walk":"^1.2.8",
7577
"ajv":"^6.12.4",
7678
"chalk":"^4.0.0",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports={
2+
rules:{
3+
"no-unused-vars":"error"
4+
}
5+
};

‎tools/check-emfile-handling.js‎

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
*@fileoverview A utility to test that ESLint doesn't crash with EMFILE/ENFILE errors.
3+
*@author Nicholas C. Zakas
4+
*/
5+
6+
"use strict";
7+
8+
//------------------------------------------------------------------------------
9+
// Requirements
10+
//------------------------------------------------------------------------------
11+
12+
constfs=require("fs");
13+
const{ readFile}=require("fs/promises");
14+
const{ execSync}=require("child_process");
15+
constos=require("os");
16+
17+
//------------------------------------------------------------------------------
18+
// Helpers
19+
//------------------------------------------------------------------------------
20+
21+
constOUTPUT_DIRECTORY="tmp/emfile-check";
22+
constCONFIG_DIRECTORY="tests/fixtures/emfile";
23+
24+
/*
25+
* Every operating system has a different limit for the number of files that can
26+
* be opened at once. This number is meant to be larger than the default limit
27+
* on most systems.
28+
*
29+
* Linux systems typically start at a count of 1024 and may be increased to 4096.
30+
* MacOS Sonoma v14.4 has a limit of 10496.
31+
* Windows has no hard limit but may be limited by available memory.
32+
*/
33+
constDEFAULT_FILE_COUNT=15000;
34+
letFILE_COUNT=DEFAULT_FILE_COUNT;
35+
36+
// if the platform isn't windows, get the ulimit to see what the actual limit is
37+
if(os.platform()!=="win32"){
38+
try{
39+
FILE_COUNT=parseInt(execSync("ulimit -n").toString().trim(),10)+1;
40+
41+
console.log(`Detected Linux file limit of${FILE_COUNT}.`);
42+
43+
// if we're on a Mac, make sure the limit isn't high enough to cause a call stack error
44+
if(os.platform()==="darwin"){
45+
FILE_COUNT=Math.min(FILE_COUNT,100000);
46+
}
47+
}catch{
48+
49+
// ignore error and use default
50+
}
51+
}
52+
53+
/**
54+
* Generates files in a directory.
55+
*@returns {void}
56+
*/
57+
functiongenerateFiles(){
58+
59+
fs.mkdirSync(OUTPUT_DIRECTORY,{recursive:true});
60+
61+
for(leti=0;i<FILE_COUNT;i++){
62+
constfileName=`file_${i}.js`;
63+
constfileContent=`// This is file${i}`;
64+
65+
fs.writeFileSync(`${OUTPUT_DIRECTORY}/${fileName}`,fileContent);
66+
}
67+
68+
}
69+
70+
/**
71+
* Generates an EMFILE error by reading all files in the output directory.
72+
*@returns {Promise<Buffer[]>} A promise that resolves with the contents of all files.
73+
*/
74+
functiongenerateEmFileError(){
75+
returnPromise.all(
76+
Array.from({length:FILE_COUNT},(_,i)=>{
77+
constfileName=`file_${i}.js`;
78+
79+
returnreadFile(`${OUTPUT_DIRECTORY}/${fileName}`);
80+
})
81+
);
82+
}
83+
84+
//------------------------------------------------------------------------------
85+
// Main
86+
//------------------------------------------------------------------------------
87+
88+
console.log(`Generating${FILE_COUNT} files in${OUTPUT_DIRECTORY}...`);
89+
generateFiles();
90+
91+
console.log("Running ESLint...");
92+
execSync(`node bin/eslint.js${OUTPUT_DIRECTORY} -c${CONFIG_DIRECTORY}/eslint.config.js`,{stdio:"inherit"});
93+
console.log("✅ No errors encountered running ESLint.");
94+
95+
console.log("Checking that this number of files would cause an EMFILE error...");
96+
generateEmFileError()
97+
.then(()=>{
98+
thrownewError("EMFILE error not encountered.");
99+
})
100+
.catch(error=>{
101+
if(error.code==="EMFILE"){
102+
console.log("✅ EMFILE error encountered:",error.message);
103+
}elseif(error.code==="ENFILE"){
104+
console.log("✅ ENFILE error encountered:",error.message);
105+
}else{
106+
console.error("❌ Unexpected error encountered:",error.message);
107+
throwerror;
108+
}
109+
});

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp