import { Mutant } from '@stryker-mutator/api/core'; import { Logger } from '@stryker-mutator/api/logging'; import { ChildProcessCrashedError } from '../child-proxy/child-process-crashed-error.js'; import { OutOfMemoryError } from '../child-proxy/out-of-memory-error.js'; import { ResourceDecorator } from '../concurrent/index.js'; import { CheckerResource } from './checker-resource.js'; export class CheckerRetryDecorator extends ResourceDecorator implements CheckerResource { constructor(producer: () => CheckerResource, private readonly log: Logger) { super(producer); } public async check(checkerName: string, mutants: Mutant[]): ReturnType { return this.tryAction(() => this.innerResource.check(checkerName, mutants)); } public async group(checkerName: string, mutants: Mutant[]): ReturnType { return this.tryAction(() => this.innerResource.group(checkerName, mutants)); } private async tryAction(act: () => Promise): Promise { try { return await act(); } catch (error) { if (error instanceof ChildProcessCrashedError) { if (error instanceof OutOfMemoryError) { this.log.warn(`Checker process [${error.pid}] ran out of memory. Retrying in a new process.`); } else { this.log.warn(`Checker process [${error.pid}] crashed with exit code ${error.exitCode}. Retrying in a new process.`, error); } await this.recover(); return act(); } else { throw error; //oops } } } }