From 920410c27fc6872d73aa1660561c750e9c9042c7 Mon Sep 17 00:00:00 2001 From: Ulad Kasach Date: Sun, 18 Aug 2024 19:26:40 -0400 Subject: [PATCH] feat(wrappers): expose waitFor wrapper --- src/index.ts | 1 + src/wrappers/waitFor.ts | 64 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/wrappers/waitFor.ts diff --git a/src/index.ts b/src/index.ts index a01438a..7357109 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,3 +6,4 @@ export * from './checks/isUniDateTime'; export * from './casts/toMillisecondsSinceEpoch'; export * from './manipulate/addDuration'; export * from './manipulate/subDuration'; +export * from './wrappers/waitFor'; diff --git a/src/wrappers/waitFor.ts b/src/wrappers/waitFor.ts new file mode 100644 index 0000000..9fcb768 --- /dev/null +++ b/src/wrappers/waitFor.ts @@ -0,0 +1,64 @@ +import { HelpfulError } from '@ehmpathy/error-fns'; +import { NotUndefined, isNotUndefined } from 'type-fns'; + +import { UniDuration, toMilliseconds } from '../domain/UniDuration'; +import { sleep } from '../utils/sleep'; + +const DEFAULT_TIMEOUT: UniDuration = { seconds: 60 }; +const DEFAULT_INTERVAL: UniDuration = { seconds: 10 }; + +export class WaitForTimedOutError extends HelpfulError {} + +/** + * tactic + * .what: wait for an output + * .why: + * - enables waiting until some desired result is ready + * - ensures best practices and a pit of success contract + * - uses readable names for maintainability + */ +export const waitFor = async ( + /** + * the procedure which extracts some output that we are waiting for + * + * note + * - waitFor waits until the extractor returns a value other than `void` or `undefined` + */ + extractor: () => Promise, + + /** + * options to control the wait + */ + options?: { + /** + * the interval at which to check for completion + */ + interval?: UniDuration; + + /** + * the maximum duration to wait for, until timeout + */ + timeout?: UniDuration; + }, +): Promise> => { + // define the timeout and interval + const timeout = options?.timeout ?? DEFAULT_TIMEOUT; + const interval = options?.interval ?? DEFAULT_INTERVAL; + + // track the timestamps of interest + const startAtMSE: number = new Date().getTime(); + const timeoutAtMSE: number = startAtMSE + toMilliseconds(timeout); + + // check each interval + while (new Date().getTime() < timeoutAtMSE) { + const output = await extractor(); + if (isNotUndefined(output)) return output; + await sleep(interval); + } + + // throw an error if reached here, since it implies a timeout + throw new WaitForTimedOutError('no output returned from waitFor.extractor', { + interval, + timeout, + }); +};