Skip to content

Commit fd5d7e6

Browse files
feat: add --no-file-parallelism, --maxWorkers, --minWorkers flags (#4705)
Co-authored-by: Ari Perkkiö <[email protected]>
1 parent 7191103 commit fd5d7e6

File tree

11 files changed

+102
-31
lines changed

11 files changed

+102
-31
lines changed

docs/config/index.md

+27
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,33 @@ Pass additional arguments to `node` process in the VM context. See [Command-line
879879
Be careful when using, it as some options may crash worker, e.g. --prof, --title. See https://github.com/nodejs/node/issues/41103.
880880
:::
881881

882+
### fileParallelism
883+
884+
- **Type:** `boolean`
885+
- **Default:** `true`
886+
- **CLI:** `--no-file-parallelism`, `--fileParallelism=false`
887+
- **Version:** Since Vitest 1.1
888+
889+
Should all test files run in parallel. Setting this to `false` will override `maxWorkers` and `minWorkers` options to `1`.
890+
891+
::: tip
892+
This option doesn't affect tests running in the same file. If you want to run those in parallel, use `concurrent` option on [describe](/api/#describe-concurrent) or via [a config](#sequence-concurrent).
893+
:::
894+
895+
### maxWorkers
896+
897+
- **Type:** `number`
898+
- **Version:** Since Vitest 1.1
899+
900+
Maximum number of workers to run tests in. `poolOptions.{threads,vmThreads}.maxThreads`/`poolOptions.forks.maxForks` has higher priority.
901+
902+
### minWorkers
903+
904+
- **Type:** `number`
905+
- **Version:** Since Vitest 1.1
906+
907+
Minimum number of workers to run tests in. `poolOptions.{threads,vmThreads}.minThreads`/`poolOptions.forks.minForks` has higher priority.
908+
882909
### testTimeout
883910

884911
- **Type:** `number`

docs/guide/cli.md

+3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ Run only [benchmark](https://vitest.dev/guide/features.html#benchmarking-experim
7373
| `--poolOptions <options>` | Specify pool options |
7474
| `--poolOptions.threads.isolate` | Isolate tests in threads pool (default: `true`) |
7575
| `--poolOptions.forks.isolate` | Isolate tests in forks pool (default: `true`) |
76+
| `--fileParallelism` | Should all test files run in parallel. Use --no-parallelism to disable (default: true) |
77+
| `--maxWorkers` | Maximum number of workers to run tests in |
78+
| `--minWorkers` | Minimum number of workers to run tests in |
7679
| `--silent` | Silent console output from tests |
7780
| `--reporter <name>` | Select reporter: `default`, `verbose`, `dot`, `junit`, `json`, or a path to a custom reporter |
7881
| `--outputFile <filename/-s>` | Write test results to a file when the `--reporter=json` or `--reporter=junit` option is also specified <br /> Via [cac's dot notation] you can specify individual outputs for multiple reporters |

docs/guide/debugging.md

+7
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ vitest --inspect-brk --pool threads --poolOptions.threads.singleThread
6262
vitest --inspect-brk --pool forks --poolOptions.forks.singleFork
6363
```
6464

65+
If you are using Vitest 1.1 or higher, you can also just provide `--no-parallelism` flag:
66+
67+
```sh
68+
# If pool is unknown
69+
vitest --inspect-brk --no-file-parallelism
70+
```
71+
6572
Once Vitest starts it will stop execution and wait for you to open developer tools that can connect to [Node.js inspector](https://nodejs.org/en/docs/guides/debugging-getting-started/). You can use Chrome DevTools for this by opening `chrome://inspect` on browser.
6673

6774
In watch mode you can keep the debugger open during test re-runs by using the `--poolOptions.threads.isolate false` options.

packages/vitest/src/node/cli.ts

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ cli
3737
.option('--poolOptions <options>', 'Specify pool options')
3838
.option('--poolOptions.threads.isolate', 'Isolate tests in threads pool (default: true)')
3939
.option('--poolOptions.forks.isolate', 'Isolate tests in forks pool (default: true)')
40+
.option('--fileParallelism', 'Should all test files run in parallel. Use --no-file-parallelism to disable (default: true)')
41+
.option('--maxWorkers', 'Maximum number of workers to run tests in')
42+
.option('--minWorkers', 'Minimum number of workers to run tests in')
4043
.option('--environment <env>', 'Specify runner environment, if not running in the browser (default: node)')
4144
.option('--passWithNoTests', 'Pass when no tests found')
4245
.option('--logHeapUsage', 'Show the size of heap for each test')

packages/vitest/src/node/config.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,21 @@ export function resolveConfig(
120120
resolved.shard = { index, count }
121121
}
122122

123+
resolved.fileParallelism ??= true
124+
125+
if (!resolved.fileParallelism) {
126+
// ignore user config, parallelism cannot be implemented without limiting workers
127+
resolved.maxWorkers = 1
128+
resolved.minWorkers = 1
129+
}
130+
123131
if (resolved.inspect || resolved.inspectBrk) {
124132
const isSingleThread = resolved.pool === 'threads' && resolved.poolOptions?.threads?.singleThread
125133
const isSingleFork = resolved.pool === 'forks' && resolved.poolOptions?.forks?.singleFork
126134

127-
if (!isSingleThread && !isSingleFork) {
135+
if (resolved.fileParallelism && !isSingleThread && !isSingleFork) {
128136
const inspectOption = `--inspect${resolved.inspectBrk ? '-brk' : ''}`
129-
throw new Error(`You cannot use ${inspectOption} without "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"`)
137+
throw new Error(`You cannot use ${inspectOption} without "--no-parallelism", "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"`)
130138
}
131139
}
132140

packages/vitest/src/node/pools/child.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ export function createChildProcessPool(ctx: Vitest, { execArgv, env, forksPath }
5858
? Math.max(Math.floor(numCpus / 2), 1)
5959
: Math.max(numCpus - 1, 1)
6060

61-
const maxThreads = ctx.config.poolOptions?.forks?.maxForks ?? threadsCount
62-
const minThreads = ctx.config.poolOptions?.forks?.minForks ?? threadsCount
61+
const poolOptions = ctx.config.poolOptions?.forks ?? {}
62+
63+
const maxThreads = poolOptions.maxForks ?? ctx.config.maxWorkers ?? threadsCount
64+
const minThreads = poolOptions.minForks ?? ctx.config.minWorkers ?? threadsCount
6365

6466
const options: TinypoolOptions = {
6567
runtime: 'child_process',
@@ -70,20 +72,20 @@ export function createChildProcessPool(ctx: Vitest, { execArgv, env, forksPath }
7072

7173
env,
7274
execArgv: [
73-
...ctx.config.poolOptions?.forks?.execArgv ?? [],
75+
...poolOptions.execArgv ?? [],
7476
...execArgv,
7577
],
7678

7779
terminateTimeout: ctx.config.teardownTimeout,
80+
concurrentTasksPerWorker: 1,
7881
}
7982

80-
if (ctx.config.poolOptions?.forks?.isolate ?? true) {
83+
const isolated = poolOptions.isolate ?? true
84+
85+
if (isolated)
8186
options.isolateWorkers = true
82-
options.concurrentTasksPerWorker = 1
83-
}
8487

85-
if (ctx.config.poolOptions?.forks?.singleFork) {
86-
options.concurrentTasksPerWorker = 1
88+
if (poolOptions.singleFork || !ctx.config.fileParallelism) {
8789
options.maxThreads = 1
8890
options.minThreads = 1
8991
}
@@ -164,7 +166,7 @@ export function createChildProcessPool(ctx: Vitest, { execArgv, env, forksPath }
164166
const files = Object.values(filesByEnv).flat()
165167
const results: PromiseSettledResult<void>[] = []
166168

167-
if (ctx.config.poolOptions?.forks?.isolate ?? true) {
169+
if (isolated) {
168170
results.push(...await Promise.allSettled(files.map(({ file, environment, project }) =>
169171
runFiles(project, getConfig(project), [file], environment, invalidates))))
170172
}

packages/vitest/src/node/pools/threads.ts

+12-10
Original file line numberDiff line numberDiff line change
@@ -43,34 +43,36 @@ export function createThreadsPool(ctx: Vitest, { execArgv, env, workerPath }: Po
4343
? Math.max(Math.floor(numCpus / 2), 1)
4444
: Math.max(numCpus - 1, 1)
4545

46-
const maxThreads = ctx.config.poolOptions?.threads?.maxThreads ?? threadsCount
47-
const minThreads = ctx.config.poolOptions?.threads?.minThreads ?? threadsCount
46+
const poolOptions = ctx.config.poolOptions?.threads ?? {}
47+
48+
const maxThreads = poolOptions.maxThreads ?? ctx.config.maxWorkers ?? threadsCount
49+
const minThreads = poolOptions.minThreads ?? ctx.config.minWorkers ?? threadsCount
4850

4951
const options: TinypoolOptions = {
5052
filename: workerPath,
5153
// TODO: investigate further
5254
// It seems atomics introduced V8 Fatal Error https://github.com/vitest-dev/vitest/issues/1191
53-
useAtomics: ctx.config.poolOptions?.threads?.useAtomics ?? false,
55+
useAtomics: poolOptions.useAtomics ?? false,
5456

5557
maxThreads,
5658
minThreads,
5759

5860
env,
5961
execArgv: [
60-
...ctx.config.poolOptions?.threads?.execArgv ?? [],
62+
...poolOptions.execArgv ?? [],
6163
...execArgv,
6264
],
6365

6466
terminateTimeout: ctx.config.teardownTimeout,
67+
concurrentTasksPerWorker: 1,
6568
}
6669

67-
if (ctx.config.poolOptions?.threads?.isolate ?? true) {
70+
const isolated = poolOptions.isolate ?? true
71+
72+
if (isolated)
6873
options.isolateWorkers = true
69-
options.concurrentTasksPerWorker = 1
70-
}
7174

72-
if (ctx.config.poolOptions?.threads?.singleThread) {
73-
options.concurrentTasksPerWorker = 1
75+
if (poolOptions.singleThread || !ctx.config.fileParallelism) {
7476
options.maxThreads = 1
7577
options.minThreads = 1
7678
}
@@ -144,7 +146,7 @@ export function createThreadsPool(ctx: Vitest, { execArgv, env, workerPath }: Po
144146
const files = Object.values(filesByEnv).flat()
145147
const results: PromiseSettledResult<void>[] = []
146148

147-
if (ctx.config.poolOptions?.threads?.isolate ?? true) {
149+
if (isolated) {
148150
results.push(...await Promise.allSettled(files.map(({ file, environment, project }) =>
149151
runFiles(project, getConfig(project), [file], environment, invalidates))))
150152
}

packages/vitest/src/node/pools/typecheck.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ export function createTypecheckPool(ctx: Vitest): ProcessPool {
9696
setTimeout(() => {
9797
resolve(false)
9898
clearInterval(_i)
99-
}, 500)
99+
}, 500).unref()
100100
})
101101
const triggered = await _p
102102
if (project.typechecker && !triggered) {

packages/vitest/src/node/pools/vm-threads.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,16 @@ export function createVmThreadsPool(ctx: Vitest, { execArgv, env, vmPath }: Pool
4848
? Math.max(Math.floor(numCpus / 2), 1)
4949
: Math.max(numCpus - 1, 1)
5050

51-
const maxThreads = ctx.config.poolOptions?.vmThreads?.maxThreads ?? threadsCount
52-
const minThreads = ctx.config.poolOptions?.vmThreads?.minThreads ?? threadsCount
51+
const poolOptions = ctx.config.poolOptions?.vmThreads ?? {}
52+
53+
const maxThreads = poolOptions.maxThreads ?? ctx.config.maxWorkers ?? threadsCount
54+
const minThreads = poolOptions.minThreads ?? ctx.config.minWorkers ?? threadsCount
5355

5456
const options: TinypoolOptions = {
5557
filename: vmPath,
5658
// TODO: investigate further
5759
// It seems atomics introduced V8 Fatal Error https://github.com/vitest-dev/vitest/issues/1191
58-
useAtomics: ctx.config.poolOptions?.vmThreads?.useAtomics ?? false,
60+
useAtomics: poolOptions.useAtomics ?? false,
5961

6062
maxThreads,
6163
minThreads,
@@ -66,16 +68,16 @@ export function createVmThreadsPool(ctx: Vitest, { execArgv, env, vmPath }: Pool
6668
'--experimental-vm-modules',
6769
'--require',
6870
suppressWarningsPath,
69-
...ctx.config.poolOptions?.vmThreads?.execArgv ?? [],
71+
...poolOptions.execArgv ?? [],
7072
...execArgv,
7173
],
7274

7375
terminateTimeout: ctx.config.teardownTimeout,
76+
concurrentTasksPerWorker: 1,
7477
maxMemoryLimitBeforeRecycle: getMemoryLimit(ctx.config) || undefined,
7578
}
7679

77-
if (ctx.config.poolOptions?.vmThreads?.singleThread) {
78-
options.concurrentTasksPerWorker = 1
80+
if (poolOptions.singleThread || !ctx.config.fileParallelism) {
7981
options.maxThreads = 1
8082
options.minThreads = 1
8183
}

packages/vitest/src/types/config.ts

+17
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,23 @@ export interface InlineConfig {
294294
*/
295295
poolOptions?: PoolOptions
296296

297+
/**
298+
* Maximum number of workers to run tests in. `poolOptions.{threads,vmThreads}.maxThreads`/`poolOptions.forks.maxForks` has higher priority.
299+
*/
300+
maxWorkers?: number
301+
/**
302+
* Minimum number of workers to run tests in. `poolOptions.{threads,vmThreads}.minThreads`/`poolOptions.forks.minForks` has higher priority.
303+
*/
304+
minWorkers?: number
305+
306+
/**
307+
* Should all test files run in parallel. Doesn't affect tests running in the same file.
308+
* Setting this to `false` will override `maxWorkers` and `minWorkers` options to `1`.
309+
*
310+
* @default true
311+
*/
312+
fileParallelism?: boolean
313+
297314
/**
298315
* Automatically assign pool based on globs. The first match will be used.
299316
*

test/config/test/failures.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,19 @@ test('shard index must be smaller than count', async () => {
3333
test('inspect requires changing pool and singleThread/singleFork', async () => {
3434
const { stderr } = await runVitest({ inspect: true })
3535

36-
expect(stderr).toMatch('Error: You cannot use --inspect without "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"')
36+
expect(stderr).toMatch('Error: You cannot use --inspect without "--no-parallelism", "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"')
3737
})
3838

3939
test('inspect cannot be used with multi-threading', async () => {
4040
const { stderr } = await runVitest({ inspect: true, pool: 'threads', poolOptions: { threads: { singleThread: false } } })
4141

42-
expect(stderr).toMatch('Error: You cannot use --inspect without "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"')
42+
expect(stderr).toMatch('Error: You cannot use --inspect without "--no-parallelism", "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"')
4343
})
4444

4545
test('inspect-brk cannot be used with multi processing', async () => {
4646
const { stderr } = await runVitest({ inspect: true, pool: 'forks', poolOptions: { forks: { singleFork: false } } })
4747

48-
expect(stderr).toMatch('Error: You cannot use --inspect without "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"')
48+
expect(stderr).toMatch('Error: You cannot use --inspect without "--no-parallelism", "poolOptions.threads.singleThread" or "poolOptions.forks.singleFork"')
4949
})
5050

5151
test('c8 coverage provider is not supported', async () => {

0 commit comments

Comments
 (0)