Skip to content

Commit

Permalink
refactor(Task): Refactor task to use Promise.race
Browse files Browse the repository at this point in the history
Don't reinvent the wheel
  • Loading branch information
nicojs committed Jul 24, 2018
1 parent dd2ee86 commit cb63eab
Show file tree
Hide file tree
Showing 7 changed files with 28 additions and 42 deletions.
6 changes: 3 additions & 3 deletions packages/stryker/src/child-proxy/ChildProcessProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { File } from 'stryker-api/core';
import { getLogger } from 'stryker-api/logging';
import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol';
import { serialize, deserialize, kill, isErrnoException } from '../utils/objectUtils';
import Task from '../utils/Task';
import { Task, ExpirableTask } from '../utils/Task';
import LoggingClientContext from '../logging/LoggingClientContext';
import StrykerError from '../utils/StrykerError';
import ChildProcessCrashedError from './ChildProcessCrashedError';
Expand All @@ -24,7 +24,7 @@ export default class ChildProcessProxy<T> {

private worker: ChildProcess;
private initTask: Task;
private disposeTask: Task<void> | undefined;
private disposeTask: ExpirableTask<void> | undefined;
private currentError: StrykerError | undefined;
private workerTasks: Task<any>[] = [];
private log = getLogger(ChildProcessProxy.name);
Expand Down Expand Up @@ -203,7 +203,7 @@ export default class ChildProcessProxy<T> {
kill(this.worker.pid);
this.isDisposed = true;
};
this.disposeTask = new Task(TIMEOUT_FOR_DISPOSE);
this.disposeTask = new ExpirableTask(TIMEOUT_FOR_DISPOSE);
this.send({ kind: WorkerMessageKind.Dispose });
return this.disposeTask.promise
.then(killWorker)
Expand Down
45 changes: 17 additions & 28 deletions packages/stryker/src/utils/Task.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,48 @@
import { sleep } from './objectUtils';

/**
* Wraps a promise in a Task api for convenience.
*/
export default class Task<T = void> {
export class Task<T = void> {

private _promise: Promise<T>;
protected _promise: Promise<T>;
private resolveFn: (value?: T | PromiseLike<T>) => void;
private rejectFn: (reason: any) => void;
private _isResolved = false;
private timeout: NodeJS.Timer;

constructor(timeoutMs?: number, private timeoutHandler?: () => PromiseLike<T>) {
constructor() {
this._promise = new Promise<T>((resolve, reject) => {
this.resolveFn = resolve;
this.rejectFn = reject;
});
if (timeoutMs) {
this.timeout = setTimeout(() => this.handleTimeout(), timeoutMs);
}
}

get isResolved() {
return this._isResolved;
}

get promise() {
return this._promise;
}

handleTimeout() {
if (this.timeoutHandler) {
this.timeoutHandler().then(val => this.resolve(val));
} else {
this.resolve(undefined);
}
}

chainTo(promise: Promise<T>) {
promise.then(value => this.resolve(value), reason => this.reject(reason));
get isResolved() {
return this._isResolved;
}

resolve(result: undefined | T | PromiseLike<T>) {
this.resolveTimeout();
this._isResolved = true;
this.resolveFn(result);
}

reject(reason: any) {
this.resolveTimeout();
this._isResolved = true;
this.rejectFn(reason);
}
}

private resolveTimeout() {
if (this.timeout) {
clearTimeout(this.timeout);
}
this._isResolved = true;
/**
* A task that can expire after the given time.
* If that happens, the inner promise is resolved
*/
export class ExpirableTask<T = void> extends Task<T | void> {
constructor(timeoutMS: number) {
super();
this._promise = Promise.race([this._promise, sleep(timeoutMS)]);
}
}
2 changes: 1 addition & 1 deletion packages/stryker/src/utils/objectUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ export function kill(pid: number): Promise<void> {
});
}

export function sleep(ms: number) {
export function sleep(ms: number): Promise<void> {
return new Promise(res => {
setTimeout(res, ms);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { File, LogLevel } from 'stryker-api/core';
import { Logger } from 'stryker-api/logging';
import Echo from './Echo';
import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy';
import Task from '../../../src/utils/Task';
import { Task } from '../../../src/utils/Task';
import LoggingServer from '../../helpers/LoggingServer';
import { filter } from 'rxjs/operators';
import { Mock } from '../../helpers/producers';
Expand Down
7 changes: 3 additions & 4 deletions packages/stryker/test/unit/SandboxPoolSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import { File, LogLevel } from 'stryker-api/core';
import { TestFramework } from 'stryker-api/test_framework';
import Sandbox from '../../src/Sandbox';
import SandboxPool from '../../src/SandboxPool';
import Task from '../../src/utils/Task';
import { Task } from '../../src/utils/Task';
import '../helpers/globals';
import { Mock, config, file, mock, testFramework } from '../helpers/producers';
import LoggingClientContext from '../../src/logging/LoggingClientContext';
import { sleep } from '../../src/utils/objectUtils';

const OVERHEAD_TIME_MS = 42;
const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({
Expand Down Expand Up @@ -117,8 +118,6 @@ describe('SandboxPool', () => {
});

function tick() {
return new Promise(res => {
setTimeout(res, 0);
});
return sleep(0);
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy';
import LoggingClientContext from '../../../src/logging/LoggingClientContext';
import ChildProcessTestRunnerWorker from '../../../src/test-runner/ChildProcessTestRunnerWorker';
import TestRunnerDecorator from '../../../src/test-runner/TestRunnerDecorator';
import Task from '../../../src/utils/Task';
import { Task } from '../../../src/utils/Task';
import ChildProcessCrashedError from '../../../src/child-proxy/ChildProcessCrashedError';

describe(ChildProcessTestRunnerDecorator.name, () => {
Expand Down
6 changes: 2 additions & 4 deletions packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy';
import MutantTranspiler from '../../../src/transpiler/MutantTranspiler';
import TranspileResult from '../../../src/transpiler/TranspileResult';
import TranspilerFacade, * as transpilerFacade from '../../../src/transpiler/TranspilerFacade';
import { errorToString } from '../../../src/utils/objectUtils';
import { errorToString, sleep } from '../../../src/utils/objectUtils';
import '../../helpers/globals';
import { Mock, config, file, mock, testableMutant } from '../../helpers/producers';
import LoggingClientContext from '../../../src/logging/LoggingClientContext';
Expand Down Expand Up @@ -157,9 +157,7 @@ describe('MutantTranspiler', () => {
];
expect(actualResults).deep.eq(expectedResults);
});
const nextTick = () => new Promise(res => {
setTimeout(res, 0);
});
const nextTick = () => sleep(0);
});
});

Expand Down

0 comments on commit cb63eab

Please sign in to comment.