summaryrefslogtreecommitdiff
path: root/lib/types/fn/either.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/types/fn/either.ts')
-rw-r--r--lib/types/fn/either.ts40
1 files changed, 40 insertions, 0 deletions
diff --git a/lib/types/fn/either.ts b/lib/types/fn/either.ts
index 0f65859..ffe06d4 100644
--- a/lib/types/fn/either.ts
+++ b/lib/types/fn/either.ts
@@ -25,6 +25,7 @@ export interface IEither<E, T> extends Tagged<IEitherTag> {
readonly flatMapAsync: <_T>(mapper: Mapper<T, Promise<IEither<E, _T>>>) => Promise<IEither<E, _T>>;
readonly moveRight: <_T>(t: _T) => IEither<E, _T>;
+ readonly swap: Supplier<IEither<T, E>>;
readonly fold: <_T>(leftFolder: Mapper<E, _T>, rightFolder: Mapper<T, _T>) => _T;
readonly joinRight: <O, _T>(other: IEither<E, O>, mapper: (a: O, b: T) => _T) => IEither<E, _T>;
readonly joinRightAsync: <O, _T>(
@@ -119,6 +120,11 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> {
});
}
+ public swap(): IEither<T, E> {
+ if (isRight(this.self)) return Either.left(this.self.ok);
+ return Either.right(this.self.err);
+ }
+
static left<E, T>(e: E): IEither<E, T> {
return new Either({ err: e, _tag: ELeftTag });
}
@@ -140,4 +146,38 @@ export class Either<E, T> extends _Tagged implements IEither<E, T> {
.then((t: T) => Either.right<E, T>(t))
.catch((e: E) => Either.left<E, T>(e));
}
+
+ static async retrying<E, T>(
+ s: Supplier<Promise<IEither<E, T>>>,
+ attempts: number = 3,
+ interval: Mapper<number, Promise<void>> = (attempt) => Either.attemptWait(attempt),
+ ): Promise<IEither<E, T>> {
+ const res: IEither<T, E> = await Array(attempts)
+ .fill(0)
+ .reduce(
+ async (_result, _i, attempt) => {
+ await interval(attempt);
+ const result: IEither<T, E> = await _result;
+ return result.joinRightAsync(
+ () => s().then((s) => s.swap()),
+ (res, _prevError) => res,
+ );
+ },
+ Promise.resolve(Either.right<T, E>(<E>new Error('No attempts made'))),
+ );
+ return res.swap();
+ }
+
+ static attemptWait(
+ attempt: number,
+ backoffFactor: number = 500,
+ jitter: number = 300,
+ exponent: number = 1.3,
+ ): Promise<void> {
+ if (attempt === 0) {
+ return Promise.resolve();
+ }
+ const wait = Math.pow(exponent, attempt) * backoffFactor + jitter * Math.random() * Math.pow(exponent, attempt);
+ return new Promise((res) => setTimeout(res, wait));
+ }
}