-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: introduce
promiseall-no-unbounded-parallelism
linter rule
Since JavaScript is single-threaded, `Promise.all()` will only ever be used for I/O-bound tasks. However, I/O-parallelism isn't free either. Every async I/O-performing task launched will consume some FDs, and their amount is limited. If the amount of promises launched is a function of the input the program runs on, the system FDs might be exhausted. Some concurrency limit must be introduced. This linter rule exists to remind the programmer of that fact. It triggers on every `Promise.all()` invocation and cannot be resolved; the only solution is to think about it, and then silence this rule as proof that you thought about it.
- Loading branch information
Showing
8 changed files
with
73 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// ESTree is supposed to be used dynamically typed (from JavaScript) and | ||
// `@types/estree` only adds interface declarations, not helper functions to | ||
// type guard objects. Therefore, we make a bunch here. | ||
|
||
import * as estree from 'estree'; | ||
|
||
export function isMemberExpression(x: estree.BaseNode): x is estree.MemberExpression { | ||
return x.type === 'MemberExpression'; | ||
} | ||
|
||
export function isIdentifier(x: estree.BaseNode): x is estree.Identifier { | ||
return x.type === 'Identifier'; | ||
} |
39 changes: 39 additions & 0 deletions
39
tools/@aws-cdk/eslint-plugin/lib/rules/promiseall-no-unbounded-parallelism.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { Rule } from 'eslint'; | ||
import { isIdentifier, isMemberExpression } from '../private/type-checkers'; | ||
|
||
/** | ||
* Get the programmer to acknowledge that `Promise.all()` is potentially dangerous. | ||
* | ||
* Since JavaScript is single-threaded, `Promise.all()` will only ever be used for | ||
* I/O-bound tasks. However, I/O-parallelism isn't free either. Every async I/O-performing | ||
* task launched will consume some FDs, and their amount is limited. If the amount | ||
* of promises launched is a function of the input the program runs on, the system | ||
* FDs might be exhausted. Some concurrency limit must be introduced. | ||
* | ||
* This linter rule exists to remind the programmer of that fact. It triggers | ||
* on every `Promise.all()` invocation and cannot be resolved; the only solution | ||
* is to think about it, and then silence this rule as proof that you thought about it. | ||
* | ||
* In summary, it's fine if: | ||
* | ||
* - The arguments to `Promise.all()` is a fixed set of promises; OR | ||
* - The arguments to `Promise.all()` is throttled by a mechanism like 'p-limit' or | ||
* similar. | ||
*/ | ||
export function create(context: Rule.RuleContext): Rule.NodeListener { | ||
return { | ||
CallExpression: node => { | ||
if (isMemberExpression(node.callee) | ||
&& isIdentifier(node.callee.object) | ||
&& node.callee.object.name === 'Promise' | ||
&& isIdentifier(node.callee.property) | ||
&& node.callee.property.name === 'all') { | ||
|
||
context.report({ | ||
message: 'Ensure the number of awaited promises does not depend on program input, or their parallelism is limited using something like \'p-limit\' or similar. Acknowledge this message using \'// eslint-disable-next-line @aws-cdk/promiseall-no-unbounded-parallelism\'', | ||
node, | ||
}); | ||
} | ||
}, | ||
}; | ||
} |
1 change: 1 addition & 0 deletions
1
...ugin/test/rules/fixtures/promiseall-no-unbounded-parallelism/detect-promise-all.error.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Ensure the number of awaited promises does not depend on program input |
4 changes: 4 additions & 0 deletions
4
...lint-plugin/test/rules/fixtures/promiseall-no-unbounded-parallelism/detect-promise-all.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
async function main() { | ||
// This is trivial and shouldn't count... but it's the best we can find right now. | ||
return Promise.all([]); | ||
} |
6 changes: 6 additions & 0 deletions
6
...aws-cdk/eslint-plugin/test/rules/fixtures/promiseall-no-unbounded-parallelism/eslintrc.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
plugins: ['@aws-cdk'], | ||
rules: { | ||
'@aws-cdk/promiseall-no-unbounded-parallelism': [ 'error' ], | ||
} | ||
} |