UNPKG

durable-execution-storage-test-utils

Version:

Test utilities for validating durable-execution storage implementations

1,558 lines (1,537 loc) 121 kB
var __defProp = Object.defineProperty; var __export = (target, all2) => { for (var name in all2) __defProp(target, name, { get: all2[name], enumerable: true }); }; // src/index.ts import fs from "fs/promises"; import path from "path"; import { childTask, DurableExecutor, FINISHED_TASK_EXECUTION_STATUSES } from "durable-execution"; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Function.js var isFunction = (input) => typeof input === "function"; var dual = function(arity, body) { if (typeof arity === "function") { return function() { if (arity(arguments)) { return body.apply(this, arguments); } return (self) => body(self, ...arguments); }; } switch (arity) { case 0: case 1: throw new RangeError(`Invalid arity ${arity}`); case 2: return function(a, b) { if (arguments.length >= 2) { return body(a, b); } return function(self) { return body(self, a); }; }; case 3: return function(a, b, c) { if (arguments.length >= 3) { return body(a, b, c); } return function(self) { return body(self, a, b); }; }; case 4: return function(a, b, c, d) { if (arguments.length >= 4) { return body(a, b, c, d); } return function(self) { return body(self, a, b, c); }; }; case 5: return function(a, b, c, d, e) { if (arguments.length >= 5) { return body(a, b, c, d, e); } return function(self) { return body(self, a, b, c, d); }; }; default: return function() { if (arguments.length >= arity) { return body.apply(this, arguments); } const args = arguments; return function(self) { return body(self, ...args); }; }; } }; var identity = (a) => a; var constant = (value) => () => value; var constNull = /* @__PURE__ */ constant(null); var constUndefined = /* @__PURE__ */ constant(void 0); function pipe(a, ab, bc, cd, de, ef, fg, gh, hi) { switch (arguments.length) { case 1: return a; case 2: return ab(a); case 3: return bc(ab(a)); case 4: return cd(bc(ab(a))); case 5: return de(cd(bc(ab(a)))); case 6: return ef(de(cd(bc(ab(a))))); case 7: return fg(ef(de(cd(bc(ab(a)))))); case 8: return gh(fg(ef(de(cd(bc(ab(a))))))); case 9: return hi(gh(fg(ef(de(cd(bc(ab(a)))))))); default: { let ret = arguments[0]; for (let i = 1; i < arguments.length; i++) { ret = arguments[i](ret); } return ret; } } } // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Equivalence.js var make = (isEquivalent) => (self, that) => self === that || isEquivalent(self, that); // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/internal/doNotation.js var let_ = (map2) => dual(3, (self, name, f) => map2(self, (a) => ({ ...a, [name]: f(a) }))); var bindTo = (map2) => dual(2, (self, name) => map2(self, (a) => ({ [name]: a }))); var bind = (map2, flatMap2) => dual(3, (self, name, f) => flatMap2(self, (a) => map2(f(a), (b) => ({ ...a, [name]: b })))); // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/GlobalValue.js var globalStoreId = `effect/GlobalValue`; var globalStore; var globalValue = (id, compute) => { if (!globalStore) { globalThis[globalStoreId] ??= /* @__PURE__ */ new Map(); globalStore = globalThis[globalStoreId]; } if (!globalStore.has(id)) { globalStore.set(id, compute()); } return globalStore.get(id); }; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Predicate.js var isFunction2 = isFunction; var isRecordOrArray = (input) => typeof input === "object" && input !== null; var isObject = (input) => isRecordOrArray(input) || isFunction2(input); var hasProperty = /* @__PURE__ */ dual(2, (self, property) => isObject(self) && property in self); // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/internal/errors.js var getBugErrorMessage = (message) => `BUG: ${message} - please report an issue at https://github.com/Effect-TS/effect/issues`; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Utils.js var GenKindTypeId = /* @__PURE__ */ Symbol.for("effect/Gen/GenKind"); var isGenKind = (u) => isObject(u) && GenKindTypeId in u; var GenKindImpl = class { value; constructor(value) { this.value = value; } /** * @since 2.0.0 */ get _F() { return identity; } /** * @since 2.0.0 */ get _R() { return (_) => _; } /** * @since 2.0.0 */ get _O() { return (_) => _; } /** * @since 2.0.0 */ get _E() { return (_) => _; } /** * @since 2.0.0 */ [GenKindTypeId] = GenKindTypeId; /** * @since 2.0.0 */ [Symbol.iterator]() { return new SingleShotGen(this); } }; var SingleShotGen = class _SingleShotGen { self; called = false; constructor(self) { this.self = self; } /** * @since 2.0.0 */ next(a) { return this.called ? { value: a, done: true } : (this.called = true, { value: this.self, done: false }); } /** * @since 2.0.0 */ return(a) { return { value: a, done: true }; } /** * @since 2.0.0 */ throw(e) { throw e; } /** * @since 2.0.0 */ [Symbol.iterator]() { return new _SingleShotGen(this.self); } }; var adapter = () => function() { let x = arguments[0]; for (let i = 1; i < arguments.length; i++) { x = arguments[i](x); } return new GenKindImpl(x); }; var MUL_HI = 1481765933 >>> 0; var MUL_LO = 1284865837 >>> 0; var YieldWrapTypeId = /* @__PURE__ */ Symbol.for("effect/Utils/YieldWrap"); var YieldWrap = class { /** * @since 3.0.6 */ #value; constructor(value) { this.#value = value; } /** * @since 3.0.6 */ [YieldWrapTypeId]() { return this.#value; } }; function yieldWrapGet(self) { if (typeof self === "object" && self !== null && YieldWrapTypeId in self) { return self[YieldWrapTypeId](); } throw new Error(getBugErrorMessage("yieldWrapGet")); } var structuralRegionState = /* @__PURE__ */ globalValue("effect/Utils/isStructuralRegion", () => ({ enabled: false, tester: void 0 })); var standard = { effect_internal_function: (body) => { return body(); } }; var forced = { effect_internal_function: (body) => { try { return body(); } finally { } } }; var isNotOptimizedAway = /* @__PURE__ */ standard.effect_internal_function(() => new Error().stack)?.includes("effect_internal_function") === true; var internalCall = isNotOptimizedAway ? standard.effect_internal_function : forced.effect_internal_function; var genConstructor = function* () { }.constructor; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Hash.js var randomHashCache = /* @__PURE__ */ globalValue(/* @__PURE__ */ Symbol.for("effect/Hash/randomHashCache"), () => /* @__PURE__ */ new WeakMap()); var symbol = /* @__PURE__ */ Symbol.for("effect/Hash"); var hash = (self) => { if (structuralRegionState.enabled === true) { return 0; } switch (typeof self) { case "number": return number(self); case "bigint": return string(self.toString(10)); case "boolean": return string(String(self)); case "symbol": return string(String(self)); case "string": return string(self); case "undefined": return string("undefined"); case "function": case "object": { if (self === null) { return string("null"); } else if (self instanceof Date) { return hash(self.toISOString()); } else if (self instanceof URL) { return hash(self.href); } else if (isHash(self)) { return self[symbol](); } else { return random(self); } } default: throw new Error(`BUG: unhandled typeof ${typeof self} - please report an issue at https://github.com/Effect-TS/effect/issues`); } }; var random = (self) => { if (!randomHashCache.has(self)) { randomHashCache.set(self, number(Math.floor(Math.random() * Number.MAX_SAFE_INTEGER))); } return randomHashCache.get(self); }; var combine = (b) => (self) => self * 53 ^ b; var optimize = (n) => n & 3221225471 | n >>> 1 & 1073741824; var isHash = (u) => hasProperty(u, symbol); var number = (n) => { if (n !== n || n === Infinity) { return 0; } let h = n | 0; if (h !== n) { h ^= n * 4294967295; } while (n > 4294967295) { h ^= n /= 4294967295; } return optimize(h); }; var string = (str) => { let h = 5381, i = str.length; while (i) { h = h * 33 ^ str.charCodeAt(--i); } return optimize(h); }; var structureKeys = (o, keys) => { let h = 12289; for (let i = 0; i < keys.length; i++) { h ^= pipe(string(keys[i]), combine(hash(o[keys[i]]))); } return optimize(h); }; var structure = (o) => structureKeys(o, Object.keys(o)); var cached = function() { if (arguments.length === 1) { const self2 = arguments[0]; return function(hash3) { Object.defineProperty(self2, symbol, { value() { return hash3; }, enumerable: false }); return hash3; }; } const self = arguments[0]; const hash2 = arguments[1]; Object.defineProperty(self, symbol, { value() { return hash2; }, enumerable: false }); return hash2; }; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Equal.js var symbol2 = /* @__PURE__ */ Symbol.for("effect/Equal"); function equals() { if (arguments.length === 1) { return (self) => compareBoth(self, arguments[0]); } return compareBoth(arguments[0], arguments[1]); } function compareBoth(self, that) { if (self === that) { return true; } const selfType = typeof self; if (selfType !== typeof that) { return false; } if (selfType === "object" || selfType === "function") { if (self !== null && that !== null) { if (isEqual(self) && isEqual(that)) { if (hash(self) === hash(that) && self[symbol2](that)) { return true; } else { return structuralRegionState.enabled && structuralRegionState.tester ? structuralRegionState.tester(self, that) : false; } } else if (self instanceof Date && that instanceof Date) { return self.toISOString() === that.toISOString(); } else if (self instanceof URL && that instanceof URL) { return self.href === that.href; } } if (structuralRegionState.enabled) { if (Array.isArray(self) && Array.isArray(that)) { return self.length === that.length && self.every((v, i) => compareBoth(v, that[i])); } if (Object.getPrototypeOf(self) === Object.prototype && Object.getPrototypeOf(self) === Object.prototype) { const keysSelf = Object.keys(self); const keysThat = Object.keys(that); if (keysSelf.length === keysThat.length) { for (const key of keysSelf) { if (!(key in that && compareBoth(self[key], that[key]))) { return structuralRegionState.tester ? structuralRegionState.tester(self, that) : false; } } return true; } } return structuralRegionState.tester ? structuralRegionState.tester(self, that) : false; } } return structuralRegionState.enabled && structuralRegionState.tester ? structuralRegionState.tester(self, that) : false; } var isEqual = (u) => hasProperty(u, symbol2); var equivalence = () => equals; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Inspectable.js var NodeInspectSymbol = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom"); var toJSON = (x) => { try { if (hasProperty(x, "toJSON") && isFunction2(x["toJSON"]) && x["toJSON"].length === 0) { return x.toJSON(); } else if (Array.isArray(x)) { return x.map(toJSON); } } catch { return {}; } return redact(x); }; var format = (x) => JSON.stringify(x, null, 2); var BaseProto = { toJSON() { return toJSON(this); }, [NodeInspectSymbol]() { return this.toJSON(); }, toString() { return format(this.toJSON()); } }; var Class = class { /** * @since 2.0.0 */ [NodeInspectSymbol]() { return this.toJSON(); } /** * @since 2.0.0 */ toString() { return format(this.toJSON()); } }; var symbolRedactable = /* @__PURE__ */ Symbol.for("effect/Inspectable/Redactable"); var isRedactable = (u) => typeof u === "object" && u !== null && symbolRedactable in u; var redactableState = /* @__PURE__ */ globalValue("effect/Inspectable/redactableState", () => ({ fiberRefs: void 0 })); var redact = (u) => { if (isRedactable(u) && redactableState.fiberRefs !== void 0) { return u[symbolRedactable](redactableState.fiberRefs); } return u; }; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Pipeable.js var pipeArguments = (self, args) => { switch (args.length) { case 0: return self; case 1: return args[0](self); case 2: return args[1](args[0](self)); case 3: return args[2](args[1](args[0](self))); case 4: return args[3](args[2](args[1](args[0](self)))); case 5: return args[4](args[3](args[2](args[1](args[0](self))))); case 6: return args[5](args[4](args[3](args[2](args[1](args[0](self)))))); case 7: return args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))); case 8: return args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self)))))))); case 9: return args[8](args[7](args[6](args[5](args[4](args[3](args[2](args[1](args[0](self))))))))); default: { let ret = self; for (let i = 0, len = args.length; i < len; i++) { ret = args[i](ret); } return ret; } } }; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/internal/opCodes/effect.js var OP_COMMIT = "Commit"; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/internal/version.js var moduleVersion = "3.17.13"; var getCurrentVersion = () => moduleVersion; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/internal/effectable.js var EffectTypeId = /* @__PURE__ */ Symbol.for("effect/Effect"); var StreamTypeId = /* @__PURE__ */ Symbol.for("effect/Stream"); var SinkTypeId = /* @__PURE__ */ Symbol.for("effect/Sink"); var ChannelTypeId = /* @__PURE__ */ Symbol.for("effect/Channel"); var effectVariance = { /* c8 ignore next */ _R: (_) => _, /* c8 ignore next */ _E: (_) => _, /* c8 ignore next */ _A: (_) => _, _V: /* @__PURE__ */ getCurrentVersion() }; var sinkVariance = { /* c8 ignore next */ _A: (_) => _, /* c8 ignore next */ _In: (_) => _, /* c8 ignore next */ _L: (_) => _, /* c8 ignore next */ _E: (_) => _, /* c8 ignore next */ _R: (_) => _ }; var channelVariance = { /* c8 ignore next */ _Env: (_) => _, /* c8 ignore next */ _InErr: (_) => _, /* c8 ignore next */ _InElem: (_) => _, /* c8 ignore next */ _InDone: (_) => _, /* c8 ignore next */ _OutErr: (_) => _, /* c8 ignore next */ _OutElem: (_) => _, /* c8 ignore next */ _OutDone: (_) => _ }; var EffectPrototype = { [EffectTypeId]: effectVariance, [StreamTypeId]: effectVariance, [SinkTypeId]: sinkVariance, [ChannelTypeId]: channelVariance, [symbol2](that) { return this === that; }, [symbol]() { return cached(this, random(this)); }, [Symbol.iterator]() { return new SingleShotGen(new YieldWrap(this)); }, pipe() { return pipeArguments(this, arguments); } }; var StructuralPrototype = { [symbol]() { return cached(this, structure(this)); }, [symbol2](that) { const selfKeys = Object.keys(this); const thatKeys = Object.keys(that); if (selfKeys.length !== thatKeys.length) { return false; } for (const key of selfKeys) { if (!(key in that && equals(this[key], that[key]))) { return false; } } return true; } }; var CommitPrototype = { ...EffectPrototype, _op: OP_COMMIT }; var StructuralCommitPrototype = { ...CommitPrototype, ...StructuralPrototype }; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/internal/option.js var TypeId = /* @__PURE__ */ Symbol.for("effect/Option"); var CommonProto = { ...EffectPrototype, [TypeId]: { _A: (_) => _ }, [NodeInspectSymbol]() { return this.toJSON(); }, toString() { return format(this.toJSON()); } }; var SomeProto = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(CommonProto), { _tag: "Some", _op: "Some", [symbol2](that) { return isOption(that) && isSome(that) && equals(this.value, that.value); }, [symbol]() { return cached(this, combine(hash(this._tag))(hash(this.value))); }, toJSON() { return { _id: "Option", _tag: this._tag, value: toJSON(this.value) }; } }); var NoneHash = /* @__PURE__ */ hash("None"); var NoneProto = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(CommonProto), { _tag: "None", _op: "None", [symbol2](that) { return isOption(that) && isNone(that); }, [symbol]() { return NoneHash; }, toJSON() { return { _id: "Option", _tag: this._tag }; } }); var isOption = (input) => hasProperty(input, TypeId); var isNone = (fa) => fa._tag === "None"; var isSome = (fa) => fa._tag === "Some"; var none = /* @__PURE__ */ Object.create(NoneProto); var some = (value) => { const a = Object.create(SomeProto); a.value = value; return a; }; // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/internal/either.js var TypeId2 = /* @__PURE__ */ Symbol.for("effect/Either"); var CommonProto2 = { ...EffectPrototype, [TypeId2]: { _R: (_) => _ }, [NodeInspectSymbol]() { return this.toJSON(); }, toString() { return format(this.toJSON()); } }; var RightProto = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(CommonProto2), { _tag: "Right", _op: "Right", [symbol2](that) { return isEither(that) && isRight(that) && equals(this.right, that.right); }, [symbol]() { return combine(hash(this._tag))(hash(this.right)); }, toJSON() { return { _id: "Either", _tag: this._tag, right: toJSON(this.right) }; } }); var LeftProto = /* @__PURE__ */ Object.assign(/* @__PURE__ */ Object.create(CommonProto2), { _tag: "Left", _op: "Left", [symbol2](that) { return isEither(that) && isLeft(that) && equals(this.left, that.left); }, [symbol]() { return combine(hash(this._tag))(hash(this.left)); }, toJSON() { return { _id: "Either", _tag: this._tag, left: toJSON(this.left) }; } }); var isEither = (input) => hasProperty(input, TypeId2); var isLeft = (ma) => ma._tag === "Left"; var isRight = (ma) => ma._tag === "Right"; var left = (left2) => { const a = Object.create(LeftProto); a.left = left2; return a; }; var right = (right2) => { const a = Object.create(RightProto); a.right = right2; return a; }; var getLeft = (self) => isRight(self) ? none : some(self.left); var getRight = (self) => isLeft(self) ? none : some(self.right); // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Option.js var Option_exports = {}; __export(Option_exports, { Do: () => Do, TypeId: () => TypeId3, all: () => all, andThen: () => andThen, ap: () => ap, as: () => as, asVoid: () => asVoid, bind: () => bind2, bindTo: () => bindTo2, composeK: () => composeK, contains: () => contains, containsWith: () => containsWith, exists: () => exists, filter: () => filter, filterMap: () => filterMap, firstSomeOf: () => firstSomeOf, flatMap: () => flatMap, flatMapNullable: () => flatMapNullable, flatten: () => flatten, fromIterable: () => fromIterable, fromNullable: () => fromNullable, gen: () => gen, getEquivalence: () => getEquivalence, getLeft: () => getLeft2, getOrElse: () => getOrElse, getOrNull: () => getOrNull, getOrThrow: () => getOrThrow, getOrThrowWith: () => getOrThrowWith, getOrUndefined: () => getOrUndefined, getOrder: () => getOrder, getRight: () => getRight2, isNone: () => isNone2, isOption: () => isOption2, isSome: () => isSome2, let: () => let_2, lift2: () => lift2, liftNullable: () => liftNullable, liftPredicate: () => liftPredicate, liftThrowable: () => liftThrowable, map: () => map, match: () => match, mergeWith: () => mergeWith, none: () => none2, orElse: () => orElse, orElseEither: () => orElseEither, orElseSome: () => orElseSome, partitionMap: () => partitionMap, product: () => product, productMany: () => productMany, reduceCompact: () => reduceCompact, some: () => some2, tap: () => tap, toArray: () => toArray, toRefinement: () => toRefinement, void: () => void_, zipLeft: () => zipLeft, zipRight: () => zipRight, zipWith: () => zipWith }); // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Order.js var make2 = (compare) => (self, that) => self === that ? 0 : compare(self, that); // ../node_modules/.pnpm/effect@3.17.13/node_modules/effect/dist/esm/Option.js var TypeId3 = /* @__PURE__ */ Symbol.for("effect/Option"); var none2 = () => none; var some2 = some; var isOption2 = isOption; var isNone2 = isNone; var isSome2 = isSome; var match = /* @__PURE__ */ dual(2, (self, { onNone, onSome }) => isNone2(self) ? onNone() : onSome(self.value)); var toRefinement = (f) => (a) => isSome2(f(a)); var fromIterable = (collection) => { for (const a of collection) { return some2(a); } return none2(); }; var getRight2 = getRight; var getLeft2 = getLeft; var getOrElse = /* @__PURE__ */ dual(2, (self, onNone) => isNone2(self) ? onNone() : self.value); var orElse = /* @__PURE__ */ dual(2, (self, that) => isNone2(self) ? that() : self); var orElseSome = /* @__PURE__ */ dual(2, (self, onNone) => isNone2(self) ? some2(onNone()) : self); var orElseEither = /* @__PURE__ */ dual(2, (self, that) => isNone2(self) ? map(that(), right) : map(self, left)); var firstSomeOf = (collection) => { let out = none2(); for (out of collection) { if (isSome2(out)) { return out; } } return out; }; var fromNullable = (nullableValue) => nullableValue == null ? none2() : some2(nullableValue); var liftNullable = (f) => (...a) => fromNullable(f(...a)); var getOrNull = /* @__PURE__ */ getOrElse(constNull); var getOrUndefined = /* @__PURE__ */ getOrElse(constUndefined); var liftThrowable = (f) => (...a) => { try { return some2(f(...a)); } catch { return none2(); } }; var getOrThrowWith = /* @__PURE__ */ dual(2, (self, onNone) => { if (isSome2(self)) { return self.value; } throw onNone(); }); var getOrThrow = /* @__PURE__ */ getOrThrowWith(() => new Error("getOrThrow called on a None")); var map = /* @__PURE__ */ dual(2, (self, f) => isNone2(self) ? none2() : some2(f(self.value))); var as = /* @__PURE__ */ dual(2, (self, b) => map(self, () => b)); var asVoid = /* @__PURE__ */ as(void 0); var void_ = /* @__PURE__ */ some2(void 0); var flatMap = /* @__PURE__ */ dual(2, (self, f) => isNone2(self) ? none2() : f(self.value)); var andThen = /* @__PURE__ */ dual(2, (self, f) => flatMap(self, (a) => { const b = isFunction(f) ? f(a) : f; return isOption2(b) ? b : some2(b); })); var flatMapNullable = /* @__PURE__ */ dual(2, (self, f) => isNone2(self) ? none2() : fromNullable(f(self.value))); var flatten = /* @__PURE__ */ flatMap(identity); var zipRight = /* @__PURE__ */ dual(2, (self, that) => flatMap(self, () => that)); var zipLeft = /* @__PURE__ */ dual(2, (self, that) => tap(self, () => that)); var composeK = /* @__PURE__ */ dual(2, (afb, bfc) => (a) => flatMap(afb(a), bfc)); var tap = /* @__PURE__ */ dual(2, (self, f) => flatMap(self, (a) => map(f(a), () => a))); var product = (self, that) => isSome2(self) && isSome2(that) ? some2([self.value, that.value]) : none2(); var productMany = (self, collection) => { if (isNone2(self)) { return none2(); } const out = [self.value]; for (const o of collection) { if (isNone2(o)) { return none2(); } out.push(o.value); } return some2(out); }; var all = (input) => { if (Symbol.iterator in input) { const out2 = []; for (const o of input) { if (isNone2(o)) { return none2(); } out2.push(o.value); } return some2(out2); } const out = {}; for (const key of Object.keys(input)) { const o = input[key]; if (isNone2(o)) { return none2(); } out[key] = o.value; } return some2(out); }; var zipWith = /* @__PURE__ */ dual(3, (self, that, f) => map(product(self, that), ([a, b]) => f(a, b))); var ap = /* @__PURE__ */ dual(2, (self, that) => zipWith(self, that, (f, a) => f(a))); var reduceCompact = /* @__PURE__ */ dual(3, (self, b, f) => { let out = b; for (const oa of self) { if (isSome2(oa)) { out = f(out, oa.value); } } return out; }); var toArray = (self) => isNone2(self) ? [] : [self.value]; var partitionMap = /* @__PURE__ */ dual(2, (self, f) => { if (isNone2(self)) { return [none2(), none2()]; } const e = f(self.value); return isLeft(e) ? [some2(e.left), none2()] : [none2(), some2(e.right)]; }); var filterMap = flatMap; var filter = /* @__PURE__ */ dual(2, (self, predicate) => filterMap(self, (b) => predicate(b) ? some(b) : none)); var getEquivalence = (isEquivalent) => make((x, y) => isNone2(x) ? isNone2(y) : isNone2(y) ? false : isEquivalent(x.value, y.value)); var getOrder = (O) => make2((self, that) => isSome2(self) ? isSome2(that) ? O(self.value, that.value) : 1 : -1); var lift2 = (f) => dual(2, (self, that) => zipWith(self, that, f)); var liftPredicate = /* @__PURE__ */ dual(2, (b, predicate) => predicate(b) ? some2(b) : none2()); var containsWith = (isEquivalent) => dual(2, (self, a) => isNone2(self) ? false : isEquivalent(self.value, a)); var _equivalence = /* @__PURE__ */ equivalence(); var contains = /* @__PURE__ */ containsWith(_equivalence); var exists = /* @__PURE__ */ dual(2, (self, refinement) => isNone2(self) ? false : refinement(self.value)); var bindTo2 = /* @__PURE__ */ bindTo(map); var let_2 = /* @__PURE__ */ let_(map); var bind2 = /* @__PURE__ */ bind(map, flatMap); var Do = /* @__PURE__ */ some2({}); var adapter2 = /* @__PURE__ */ adapter(); var gen = (...args) => { const f = args.length === 1 ? args[0] : args[1].bind(args[0]); const iterator = f(adapter2); let state = iterator.next(); while (!state.done) { const current = isGenKind(state.value) ? state.value.value : yieldWrapGet(state.value); if (isNone2(current)) { return current; } state = iterator.next(current.value); } return some2(state.value); }; var mergeWith = (f) => (o1, o2) => { if (isNone2(o1)) { return o2; } else if (isNone2(o2)) { return o1; } return some2(f(o1.value, o2.value)); }; // src/index.ts import { customAlphabet } from "nanoid"; import { isObject as isObject2 } from "@gpahal/std/objects"; import { sleep } from "@gpahal/std/promises"; async function runStorageTest(storage, { storageCleanup, enableStorageBatching = false, storageBackgroundBatchingProcessIntraBatchSleepMs = 10 } = {}) { const executor = await DurableExecutor.make(storage, { logLevel: "error", backgroundProcessIntraBatchSleepMs: 50, enableStorageBatching, storageBackgroundBatchingProcessIntraBatchSleepMs }); await executor.start(); try { try { await runDurableExecutorTest(executor, storage); } finally { await executor.shutdown(); } await runStorageOperationsTest(storage); } finally { if (storageCleanup) { await storageCleanup(); } } } async function runDurableExecutorTest(executor, storage) { const taskB1 = executor.task({ id: "b1", timeoutMs: 5e3, run: (ctx, input) => { return { name: input.name, taskB1Output: `Hello from task B1, ${input.name}!` }; } }); const taskB2 = executor.task({ id: "b2", timeoutMs: 1e3, run: (ctx, input) => { return { name: input.name, taskB1Output: input.taskB1Output, taskB2Output: `Hello from task B2, ${input.name}!` }; } }); const taskB3 = executor.task({ id: "b3", timeoutMs: 5e3, run: (ctx, input) => { return { taskB1Output: input.taskB1Output, taskB2Output: input.taskB2Output, taskB3Output: `Hello from task B3, ${input.name}!` }; } }); const taskB = executor.sequentialTasks("b", [taskB1, taskB2, taskB3]); const taskA1 = executor.task({ id: "a1", timeoutMs: 5e3, run: (ctx, input) => { return `Hello from task A1, ${input.name}!`; } }); const taskA2 = executor.task({ id: "a2", timeoutMs: 1e3, run: (ctx, input) => { return `Hello from task A2, ${input.name}!`; } }); const taskA3 = executor.task({ id: "a3", timeoutMs: 5e3, run: (ctx, input) => { return `Hello from task A3, ${input.name}!`; } }); const taskA = executor.parentTask({ id: "a", timeoutMs: 5e3, runParent: (ctx, input) => { return { output: `Hello from task A, ${input.name}!`, children: [ childTask(taskA1, { name: input.name }), childTask(taskA2, { name: input.name }), childTask(taskA3, { name: input.name }) ] }; }, finalize: { id: "taskAFinalize", timeoutMs: 5e3, run: (ctx, { output, children }) => { const child0 = children[0]; const child1 = children[1]; const child2 = children[2]; if (child0.status !== "completed" || child1.status !== "completed" || child2.status !== "completed") { throw new Error("Failed"); } return { taskAOutput: output, taskA1Output: child0.output, taskA2Output: child1.output, taskA3Output: child2.output }; } } }); const rootTask = executor.parentTask({ id: "root", timeoutMs: 5e3, runParent: (ctx, input) => { return { output: `Hello from root task, ${input.name}!`, children: [childTask(taskA, { name: input.name }), childTask(taskB, { name: input.name })] }; }, finalize: { id: "rootFinalize", timeoutMs: 5e3, run: (ctx, { output, children }) => { const child0 = children[0]; const child1 = children[1]; if (child0.status !== "completed" || child1.status !== "completed") { throw new Error("Failed"); } const taskAOutput = child0.output; const taskBOutput = child1.output; return { rootOutput: output, taskAOutput: taskAOutput.taskAOutput, taskA1Output: taskAOutput.taskA1Output, taskA2Output: taskAOutput.taskA2Output, taskA3Output: taskAOutput.taskA3Output, taskB1Output: taskBOutput.taskB1Output, taskB2Output: taskBOutput.taskB2Output, taskB3Output: taskBOutput.taskB3Output }; } } }); const concurrentTasks = []; for (let i = 0; i < 250; i++) { concurrentTasks.push( executor.task({ id: `t${i}`, timeoutMs: 5e3, run: async (ctx, input) => { await sleep(10 * Math.random()); return `Hello from task T${i}, ${input}!`; } }) ); } const retryTask = executor.task({ id: "retry", retryOptions: { maxAttempts: 3 }, timeoutMs: 5e3, run: (ctx) => { if (ctx.attempt < 2) { throw new Error("Failed"); } return "Success"; } }); const failingTask = executor.task({ id: "failing", timeoutMs: 5e3, run: () => { throw new Error("Failed"); } }); const parentTaskWithFailingChild = executor.parentTask({ id: "parentWithFailingChild", timeoutMs: 5e3, runParent: () => { return { output: void 0, children: [childTask(failingTask)] }; }, finalize: { id: "parentWithFailingChildFinalize", timeoutMs: 1e3, run: (ctx, { children }) => { const child = children[0]; if (child.status !== "completed") { throw new Error("Failed"); } return "success"; } } }); const parentTaskWithFailingFinalizeTask = executor.parentTask({ id: "parentWithFailingFinalizeTask", timeoutMs: 5e3, runParent: () => { return { output: void 0, children: [childTask(taskA1, { name: "world" })] }; }, finalize: { id: "parentWithFailingFinalizeTaskFinalize", timeoutMs: 1e3, run: () => { throw new Error("Failed"); } } }); const concurrentChildTask = executor.task({ id: "concurrent_child", timeoutMs: 1e4, run: async (_, index) => { await sleep(1); return index; } }); const concurrentParentTask = executor.parentTask({ id: "concurrent_parent", timeoutMs: 1e3, runParent: async () => { await sleep(1); return { output: void 0, children: Array.from({ length: 500 }, (_, index) => ({ task: concurrentChildTask, input: index })) }; } }); let value; setTimeout(() => { value = 10; }, 1e3); const iterationTask = executor.task({ id: "iteration", sleepMsBeforeRun: 100, timeoutMs: 1e3, run: () => { return value == null ? { isDone: false } : { isDone: true, output: value }; } }); const loopingTask = executor.loopingTask("looping", iterationTask, 20); const sleepingTask = executor.sleepingTask({ id: "test", timeoutMs: 3e5 }); const parentTaskWithSleepingTask = executor.parentTask({ id: "parent", timeoutMs: 1e3, runParent: () => { return { output: "parent_output", children: [childTask(sleepingTask, "test_unique_id")] }; }, finalize: { id: "finalizeTask", timeoutMs: 1e3, run: (ctx, { children }) => { const child = children[0]; if (child.status !== "completed") { throw new Error("Finalize task failed"); } return child.output; } } }); let closeTestExecutionCount = 0; const closeTestTask = executor.task({ id: "closeTestTask", timeoutMs: 1e3, run: () => { closeTestExecutionCount++; return "test"; } }); const closeTestParentTask = executor.parentTask({ id: "closeTestParentTask", timeoutMs: 1e3, runParent: () => { return { output: "parent_output", children: [childTask(closeTestTask)] }; } }); console.log("=> Enqueuing tasks"); const rootTaskHandle = await executor.enqueueTask(rootTask, { name: "world" }); const concurrentTaskHandles = await Promise.all( concurrentTasks.map((task) => executor.enqueueTask(task, "world")) ); const retryTaskHandle = await executor.enqueueTask(retryTask); const failingTaskHandle = await executor.enqueueTask(failingTask); const parentTaskWithFailingChildHandle = await executor.enqueueTask(parentTaskWithFailingChild); const parentTaskWithFailingFinalizeTaskHandle = await executor.enqueueTask( parentTaskWithFailingFinalizeTask ); const concurrentParentTaskHandle = await executor.enqueueTask(concurrentParentTask); const loopingTaskHandle = await executor.enqueueTask(loopingTask); const parentTaskWithSleepingTaskHandle = await executor.enqueueTask(parentTaskWithSleepingTask); const closeTestTaskHandle = await executor.enqueueTask(closeTestParentTask); console.log("=> Waiting for root task"); const finishedExecution = await rootTaskHandle.waitAndGetFinishedExecution({ pollingIntervalMs: 50 }); expect(finishedExecution.status).toBe("completed"); assert(finishedExecution.status === "completed"); expect(finishedExecution.taskId).toBe("root"); expect(finishedExecution.executionId).toMatch(/^te_/); expect(finishedExecution.output).toBeDefined(); expect(finishedExecution.output.taskAOutput).toBe("Hello from task A, world!"); expect(finishedExecution.output.taskA1Output).toBe("Hello from task A1, world!"); expect(finishedExecution.output.taskA2Output).toBe("Hello from task A2, world!"); expect(finishedExecution.output.taskA3Output).toBe("Hello from task A3, world!"); expect(finishedExecution.output.taskB1Output).toBe("Hello from task B1, world!"); expect(finishedExecution.output.taskB2Output).toBe("Hello from task B2, world!"); expect(finishedExecution.output.taskB3Output).toBe("Hello from task B3, world!"); expect(finishedExecution.startedAt).toBeInstanceOf(Date); expect(finishedExecution.waitingForChildrenStartedAt).toBeInstanceOf(Date); expect(finishedExecution.waitingForFinalizeStartedAt).toBeInstanceOf(Date); expect(finishedExecution.finishedAt).toBeInstanceOf(Date); expect(finishedExecution.finishedAt.getTime()).toBeGreaterThanOrEqual( finishedExecution.startedAt.getTime() ); console.log("=> Waiting for concurrent tasks"); const concurrentFinishedExecutions = await Promise.all( concurrentTaskHandles.map( (handle) => handle.waitAndGetFinishedExecution({ pollingIntervalMs: 50 }) ) ); for (const [i, execution] of concurrentFinishedExecutions.entries()) { expect(execution.status).toBe("completed"); assert(execution.status === "completed"); expect(execution.taskId).toMatch(/^t\d+$/); expect(execution.executionId).toMatch(/^te_/); expect(execution.output).toBeDefined(); expect(execution.output).toBe(`Hello from task T${i}, world!`); expect(execution.startedAt).toBeInstanceOf(Date); expect(execution.finishedAt).toBeInstanceOf(Date); expect(execution.finishedAt.getTime()).toBeGreaterThanOrEqual(execution.startedAt.getTime()); } console.log("=> Waiting for retry task"); const retryExecution = await retryTaskHandle.waitAndGetFinishedExecution({ pollingIntervalMs: 50 }); expect(retryExecution.status).toBe("completed"); assert(retryExecution.status === "completed"); expect(retryExecution.taskId).toBe("retry"); expect(retryExecution.executionId).toMatch(/^te_/); expect(retryExecution.output).toBe("Success"); expect(retryExecution.retryAttempts).toBe(2); expect(retryExecution.startedAt).toBeInstanceOf(Date); expect(retryExecution.finishedAt).toBeInstanceOf(Date); expect(retryExecution.finishedAt.getTime()).toBeGreaterThanOrEqual( retryExecution.startedAt.getTime() ); const failingExecution = await failingTaskHandle.waitAndGetFinishedExecution({ pollingIntervalMs: 50 }); expect(failingExecution.status).toBe("failed"); assert(failingExecution.status === "failed"); expect(failingExecution.taskId).toBe("failing"); expect(failingExecution.executionId).toMatch(/^te_/); expect(failingExecution.error).toBeDefined(); expect(failingExecution.error.message).toBe("Failed"); expect(failingExecution.startedAt).toBeInstanceOf(Date); expect(failingExecution.finishedAt).toBeInstanceOf(Date); expect(failingExecution.finishedAt.getTime()).toBeGreaterThanOrEqual( failingExecution.startedAt.getTime() ); console.log("=> Waiting for parent task with failing child"); const parentTaskWithFailingChildExecution = await parentTaskWithFailingChildHandle.waitAndGetFinishedExecution({ pollingIntervalMs: 50 }); expect(parentTaskWithFailingChildExecution.status).toBe("finalize_failed"); assert(parentTaskWithFailingChildExecution.status === "finalize_failed"); expect(parentTaskWithFailingChildExecution.taskId).toBe("parentWithFailingChild"); expect(parentTaskWithFailingChildExecution.error).toBeDefined(); expect(parentTaskWithFailingChildExecution.error.message).toBe("Failed"); expect(parentTaskWithFailingChildExecution.startedAt).toBeInstanceOf(Date); expect(parentTaskWithFailingChildExecution.finishedAt).toBeInstanceOf(Date); expect(parentTaskWithFailingChildExecution.finishedAt.getTime()).toBeGreaterThanOrEqual( parentTaskWithFailingChildExecution.startedAt.getTime() ); console.log("=> Waiting for parent task with failing finalize task"); const parentTaskWithFailingFinalizeTaskExecution = await parentTaskWithFailingFinalizeTaskHandle.waitAndGetFinishedExecution({ pollingIntervalMs: 50 }); expect(parentTaskWithFailingFinalizeTaskExecution.status).toBe("finalize_failed"); assert(parentTaskWithFailingFinalizeTaskExecution.status === "finalize_failed"); expect(parentTaskWithFailingFinalizeTaskExecution.taskId).toBe("parentWithFailingFinalizeTask"); expect(parentTaskWithFailingFinalizeTaskExecution.error).toBeDefined(); expect(parentTaskWithFailingFinalizeTaskExecution.error.message).toBe("Failed"); expect(parentTaskWithFailingFinalizeTaskExecution.startedAt).toBeInstanceOf(Date); expect(parentTaskWithFailingFinalizeTaskExecution.finishedAt).toBeInstanceOf(Date); expect(parentTaskWithFailingFinalizeTaskExecution.finishedAt.getTime()).toBeGreaterThanOrEqual( parentTaskWithFailingFinalizeTaskExecution.startedAt.getTime() ); console.log("=> Waiting for concurrent parent task"); const concurrentParentTaskExecution = await concurrentParentTaskHandle.waitAndGetFinishedExecution({ pollingIntervalMs: 50 }); expect(concurrentParentTaskExecution.status).toBe("completed"); assert(concurrentParentTaskExecution.status === "completed"); expect(concurrentParentTaskExecution.taskId).toBe("concurrent_parent"); expect(concurrentParentTaskExecution.output).toBeDefined(); expect(concurrentParentTaskExecution.output.children).toHaveLength(500); for (const [i, childTaskOutput] of concurrentParentTaskExecution.output.children.entries()) { expect(childTaskOutput.status).toBe("completed"); assert(childTaskOutput.status === "completed"); expect(childTaskOutput.output).toBeDefined(); expect(childTaskOutput.output).toBe(i); } expect(concurrentParentTaskExecution.startedAt).toBeInstanceOf(Date); expect(concurrentParentTaskExecution.waitingForChildrenStartedAt).toBeInstanceOf(Date); expect(concurrentParentTaskExecution.waitingForFinalizeStartedAt).toBeUndefined(); console.log("=> Waiting for looping task"); const loopingTaskExecution = await loopingTaskHandle.waitAndGetFinishedExecution({ pollingIntervalMs: 250 }); expect(loopingTaskExecution.status).toBe("completed"); assert(loopingTaskExecution.status === "completed"); expect(loopingTaskExecution.taskId).toBe("looping"); expect(loopingTaskExecution.output).toBeDefined(); expect(loopingTaskExecution.output.isSuccess).toBe(true); assert(loopingTaskExecution.output.isSuccess); expect(loopingTaskExecution.output.output).toBe(10); expect(loopingTaskExecution.startedAt).toBeInstanceOf(Date); expect(loopingTaskExecution.waitingForChildrenStartedAt).toBeInstanceOf(Date); expect(loopingTaskExecution.waitingForFinalizeStartedAt).toBeInstanceOf(Date); expect(loopingTaskExecution.finishedAt).toBeInstanceOf(Date); expect(loopingTaskExecution.finishedAt.getTime()).toBeGreaterThanOrEqual( loopingTaskExecution.startedAt.getTime() ); console.log("=> Waiting for parent task with sleeping task"); while (true) { const execution = await parentTaskWithSleepingTaskHandle.getExecution(); if (FINISHED_TASK_EXECUTION_STATUSES.includes(execution.status) || execution.status === "waiting_for_children") { break; } await sleep(100); } await sleep(100); const sleepingTaskExecution = await executor.wakeupSleepingTaskExecution( sleepingTask, "test_unique_id", { status: "completed", output: "sleeping_task_output" } ); expect(sleepingTaskExecution.status).toBe("completed"); assert(sleepingTaskExecution.status === "completed"); expect(sleepingTaskExecution.output).toBe("sleeping_task_output"); expect(sleepingTaskExecution.waitingForChildrenStartedAt).toBeUndefined(); expect(sleepingTaskExecution.waitingForFinalizeStartedAt).toBeUndefined(); const parentTaskWithSleepingTaskFinishedExecution = await parentTaskWithSleepingTaskHandle.waitAndGetFinishedExecution({ pollingIntervalMs: 100 }); expect(parentTaskWithSleepingTaskFinishedExecution.status).toBe("completed"); assert(parentTaskWithSleepingTaskFinishedExecution.status === "completed"); expect(parentTaskWithSleepingTaskFinishedExecution.output).toBe("sleeping_task_output"); console.log("=> Waiting for close test task"); const closeTestFinishedExecution = await closeTestTaskHandle.waitAndGetFinishedExecution({ pollingIntervalMs: 100 }); expect(closeTestExecutionCount).toBe(1); expect(closeTestFinishedExecution.status).toBe("completed"); assert(closeTestFinishedExecution.status === "completed"); expect(closeTestFinishedExecution.output.output).toBe("parent_output"); for (let i = 0; ; i++) { const executionStorageValues = await storage.getManyById([ { executionId: closeTestFinishedExecution.executionId, filters: {} } ]); const executionStorageValue = executionStorageValues[0]; expect(executionStorageValue).toBeDefined(); assert(executionStorageValue); expect(executionStorageValue.status).toBe("completed"); expect(executionStorageValue.onChildrenFinishedProcessingStatus).toBe("processed"); expect(executionStorageValue.onChildrenFinishedProcessingFinishedAt).toBeDefined(); assert(executionStorageValue.onChildrenFinishedProcessingFinishedAt); expect(executionStorageValue.onChildrenFinishedProcessingFinishedAt).toBeGreaterThan(0); if (executionStorageValue.closeStatus === "closed") { expect(executionStorageValue.closedAt).toBeDefined(); assert(executionStorageValue.closedAt); expect(executionStorageValue.closedAt).toBeGreaterThan( executionStorageValue.onChildrenFinishedProcessingFinishedAt ); break; } if (i >= 50) { throw new Error("closeTestParentTask not closed"); } await sleep(100); } } async function runStorageOperationsTest(storage) { console.log("=> Running storage operations test"); await storage.deleteAll(); await testInsertMany(storage); await storage.deleteAll(); await testGetManyById(storage); await storage.deleteAll(); await testGetManyBySleepingTaskUniqueId(storage); await storage.deleteAll(); await testUpdateManyById(storage); await storage.deleteAll(); await testUpdateManyByIdAndInsertChildrenIfUpdated(storage); await storage.deleteAll(); await testUpdateByStatusAndStartAtLessThanAndReturn(storage); await storage.deleteAll(); await testUpdateByStatusAndOnChildrenFinishedProcessingStatusAndActiveChildrenCountZeroAndReturn( storage ); await storage.deleteAll(); await testUpdateByCloseStatusAndReturn(storage); await storage.deleteAll(); await testUpdateByStatusAndIsSleepingTaskAndExpiresAtLessThan(storage); await storage.deleteAll(); await testUpdateByOnChildrenFinishedProcessingExpiresAtLessThan(storage); await storage.deleteAll(); await testUpdateByCloseExpiresAtLessThan(storage); await storage.deleteAll(); await testUpdateByExecutorIdAndNeedsPromiseCancellationAndReturn(storage); await storage.deleteAll(); await testGetManyByParentExecutionId(storage); await storage.deleteAll(); await testUpdateManyByParentExecutionIdAndIsFinished(storage); await storage.deleteAll(); await testUpdateAndDecrementParentActiveChildrenCountByIsFinishedAndCloseStatus(storage); await storage.deleteAll(); } async function testInsertMany(storage) { const executions = [ createTaskExecutionStorageValue(), createTaskExecutionStorageValue({ root: { taskId: generateTaskId(), executionId: generateTaskExecutionId() }, parent: { taskId: generateTaskId(), executionId: generateTaskExecutionId(), indexInParentChildren: 0, isOnlyChildOfParent: false, isFinalizeOfParent: false } }) ]; executions[1].isSleepingTask = true; executions[1].sleepingTaskUniqueId = "test_unique_id"; await storage.insertMany(executions); for (const execution of executions) { const insertedExecution = (await storage.getManyById([{ executionId: execution.executionId, filters: {} }]))[0]; expect(insertedExecution).toBeDefined(); assert(insertedExecution); expect(insertedExecution.root).toStrictEqual(execution.root); expect(insertedExecution.parent).toStrictEqual(execution.parent); expect(insertedExecution.taskId).toEqual(execution.taskId); expect(insertedExecution.executionId).toEqual(execution.executionId); expect(insertedExecution.retryOptions).toEqual(execution.retryOptions); expect(insertedExecution.sleepMsBeforeRun).toEqual(execution.sleepMsBeforeRun); expect(insertedExecution.timeoutMs).toEqual(execution.timeoutMs); expect(insertedExecution.input).toEqual(execution.input); expect(insertedExecution.executorId).toBeUndefined(); expect(insertedExecution.status).toEqual("ready"); expect(insertedExecution.isFinished).toEqual(false); expect(insertedExecution.runOutput).toBeUndefined(); expect(insertedExecution.output).toBeUndefined(); expect(insertedExecution.error).toBeUndefined(); expect(insertedExecution.retryAttempts).toEqual(0); expect(insertedExecution.startAt).toBeGreaterThan(0); expect(insertedExecution.startedAt).toBeUndefined(); expect(insertedExecution.expiresAt).toBeUndefined(); expect(insertedExecution.finishedAt).toBeUndefined(); expect(insertedExecution.children).toBeUndefined(); expect(insertedExecution.active