UNPKG

2.34 kBPlain TextView Raw
1import os from 'os';
2
3import { StrykerOptions } from '@stryker-mutator/api/core';
4import { ReplaySubject, Observable, range } from 'rxjs';
5import { Disposable, tokens } from 'typed-inject';
6import { commonTokens } from '@stryker-mutator/api/plugin';
7import { Logger } from '@stryker-mutator/api/logging';
8
9export class ConcurrencyTokenProvider implements Disposable {
10 private readonly concurrencyCheckers: number;
11 private readonly concurrencyTestRunners: number;
12 private readonly testRunnerTokenSubject = new ReplaySubject<number>();
13
14 public get testRunnerToken$(): Observable<number> {
15 return this.testRunnerTokenSubject;
16 }
17 public readonly checkerToken$: Observable<number>;
18 public static readonly inject = tokens(commonTokens.options, commonTokens.logger);
19
20 constructor(options: Pick<StrykerOptions, 'checkers' | 'concurrency'>, private readonly log: Logger) {
21 const cpuCount = os.cpus().length;
22 const concurrency = options.concurrency ?? (cpuCount > 4 ? cpuCount - 1 : cpuCount);
23 if (options.checkers.length > 0) {
24 this.concurrencyCheckers = Math.max(Math.ceil(concurrency / 2), 1);
25 this.checkerToken$ = range(this.concurrencyCheckers);
26 this.concurrencyTestRunners = Math.max(Math.floor(concurrency / 2), 1);
27 log.info('Creating %s checker process(es) and %s test runner process(es).', this.concurrencyCheckers, this.concurrencyTestRunners);
28 } else {
29 this.concurrencyCheckers = 0;
30 this.checkerToken$ = range(1); // at least one checker, the `CheckerFacade` will not create worker process.
31 this.concurrencyTestRunners = concurrency;
32 log.info('Creating %s test runner process(es).', this.concurrencyTestRunners);
33 }
34 Array.from({ length: this.concurrencyTestRunners }).forEach(() => this.testRunnerTokenSubject.next(this.tick()));
35 }
36
37 public freeCheckers(): void {
38 if (this.concurrencyCheckers > 0) {
39 this.log.debug('Checking done, creating %s additional test runner process(es)', this.concurrencyCheckers);
40 for (let i = 0; i < this.concurrencyCheckers; i++) {
41 this.testRunnerTokenSubject.next(this.tick());
42 }
43 this.testRunnerTokenSubject.complete();
44 }
45 }
46
47 private count = 0;
48 private tick() {
49 return this.count++;
50 }
51
52 public dispose(): void {
53 this.testRunnerTokenSubject.complete();
54 }
55}