EdgeAIG's picture
download
raw
9.01 kB
/**
* Defines named wait points for durable workflow executions.
*
* A `DurableDeferred` has a stable name and schemas for the value that will be
* recorded later. Workflows can await it, suspend when no result exists yet, and
* resume after its result is recorded. Tokens identify the workflow name,
* execution id, and deferred name so external code can complete the correct
* wait point later.
*
* @since 4.0.0
*/
import * as Arr from "../../Array.js";
import * as Cause from "../../Cause.js";
import * as Context from "../../Context.js";
import * as Effect from "../../Effect.js";
import * as Encoding from "../../Encoding.js";
import * as Exit from "../../Exit.js";
import * as Filter from "../../Filter.js";
import { dual } from "../../Function.js";
import * as Option from "../../Option.js";
import * as Schema from "../../Schema.js";
import * as SchemaGetter from "../../SchemaGetter.js";
import * as Workflow from "./Workflow.js";
const TypeId = "~effect/workflow/DurableDeferred";
/**
* Creates a named durable deferred with optional success and error schemas for
* persisted completion.
*
* @category constructors
* @since 4.0.0
*/
export const make = (name, options) => {
const successSchema = options?.success ?? Schema.Void;
const errorSchema = options?.error ?? Schema.Never;
return {
[TypeId]: TypeId,
name,
successSchema,
errorSchema,
exitSchema: Schema.Exit(Schema.toCodecJson(successSchema), Schema.toCodecJson(errorSchema), Schema.toCodecJson(Schema.Defect())),
withActivityAttempt: Effect.gen(function* () {
const attempt = yield* CurrentAttempt;
return make(`${name}/${attempt}`, {
success: successSchema,
error: errorSchema
});
})
};
};
const EngineTag = /*#__PURE__*/Context.Service("effect/workflow/WorkflowEngine");
const InstanceTag = /*#__PURE__*/Context.Service("effect/workflow/WorkflowEngine/WorkflowInstance");
const CurrentAttempt = /*#__PURE__*/Context.Reference("effect/workflow/Activity/CurrentAttempt", {
defaultValue: () => 1
});
const await_ = /*#__PURE__*/Effect.fnUntraced(function* (self) {
const engine = yield* EngineTag;
const instance = yield* InstanceTag;
const exit = yield* Workflow.wrapActivityResult(engine.deferredResult(self), Option.isNone);
if (Option.isNone(exit)) {
return yield* Workflow.suspend(instance);
}
return yield* exit.value;
});
export {
/**
* Waits for the durable deferred, suspending the current workflow when no
* persisted completion is available.
*
* @category combinators
* @since 4.0.0
*/
await_ as await };
/**
* Runs an effect and records its exit into the durable deferred, resuming
* workflows that are waiting on that deferred.
*
* @category combinators
* @since 4.0.0
*/
export const into = /*#__PURE__*/dual(2, (effect, self) => Effect.contextWith(context => {
const engine = Context.get(context, EngineTag);
const parentInstance = Context.get(context, InstanceTag);
const instance = {
...parentInstance
};
return Effect.onExit(Effect.provideService(effect, InstanceTag, instance), Effect.fnUntraced(function* (exit) {
if (Exit.isFailure(exit)) {
const [reasons, interrupts] = Arr.partition(exit.cause.reasons, Filter.fromPredicate(Cause.isInterruptReason));
const hasInterruptsOnly = interrupts.length === exit.cause.reasons.length;
if (hasInterruptsOnly && instance.suspended) {
parentInstance.suspended = true;
return;
} else if (interrupts.length > 0) {
exit = Exit.failCause(Cause.fromReasons(reasons));
}
}
yield* engine.deferredDone(self, {
workflowName: instance.workflow._tag,
executionId: instance.executionId,
deferredName: self.name,
exit
});
}));
}));
/**
* Runs effects as a durable race, returning a previously persisted result when
* present or completing a named deferred with the first result.
*
* @category racing
* @since 4.0.0
*/
export const raceAll = options => {
const deferred = make(`raceAll/${options.name}`, {
success: options.success,
error: options.error
});
return Effect.gen(function* () {
const engine = yield* EngineTag;
const exit = yield* engine.deferredResult(deferred);
if (Option.isSome(exit)) {
return yield* Effect.flatten(exit.value);
}
return yield* into(Effect.raceAll(options.effects), deferred);
});
};
/**
* Runtime brand identifier for durable deferred tokens.
*
* @category type IDs
* @since 4.0.0
*/
export const TokenTypeId = "~effect/workflow/DurableDeferred/Token";
/**
* Schema for branded durable deferred tokens.
*
* @category token
* @since 4.0.0
*/
export const Token = /*#__PURE__*/Schema.String.pipe(/*#__PURE__*/Schema.brand(TokenTypeId));
/**
* Schema for a decoded durable deferred token containing the workflow
* name, execution ID, and deferred name.
*
* @category token
* @since 4.0.0
*/
export class TokenParsed extends /*#__PURE__*/Schema.Class("effect/workflow/DurableDeferred/TokenParsed")({
workflowName: Schema.String,
executionId: Schema.String,
deferredName: Schema.String
}) {
/**
* Encodes the parsed workflow, execution, and deferred names back into a token.
*
* @since 4.0.0
*/
get asToken() {
return Encoding.encodeBase64Url(JSON.stringify([this.workflowName, this.executionId, this.deferredName]));
}
/**
* Schema for decoding and encoding durable deferred tokens as strings.
*
* @since 4.0.0
*/
static FromString = /*#__PURE__*/Schema.String.pipe(/*#__PURE__*/Schema.decodeTo(/*#__PURE__*/Schema.fromJsonString(/*#__PURE__*/Schema.Tuple([Schema.String, Schema.String, Schema.String])), {
decode: /*#__PURE__*/SchemaGetter.decodeBase64UrlString(),
encode: /*#__PURE__*/SchemaGetter.encodeBase64Url()
}), /*#__PURE__*/Schema.decodeTo(TokenParsed, {
decode: /*#__PURE__*/SchemaGetter.transform(([workflowName, executionId, deferredName]) => new TokenParsed({
workflowName,
executionId,
deferredName
})),
encode: /*#__PURE__*/SchemaGetter.transform(parsed => [parsed.workflowName, parsed.executionId, parsed.deferredName])
}));
/**
* Decodes a durable deferred token string into its parsed components.
*
* @since 4.0.0
*/
static fromString = /*#__PURE__*/Schema.decodeSync(TokenParsed.FromString);
/**
* Encodes parsed durable deferred token components into a token string.
*
* @since 4.0.0
*/
static encode = /*#__PURE__*/Schema.encodeSync(TokenParsed.FromString);
}
/**
* Creates a token for a durable deferred using the current workflow instance's
* workflow name and execution ID.
*
* @category token
* @since 4.0.0
*/
export const token = /*#__PURE__*/Effect.fnUntraced(function* (self) {
const instance = yield* InstanceTag;
return tokenFromExecutionId(self, instance);
});
/**
* Creates a durable deferred token from an explicit workflow, execution ID,
* and deferred name.
*
* @category token
* @since 4.0.0
*/
export const tokenFromExecutionId = /*#__PURE__*/dual(2, (self, options) => new TokenParsed({
workflowName: options.workflow._tag,
executionId: options.executionId,
deferredName: self.name
}).asToken);
/**
* Creates a durable deferred token by deriving the workflow execution ID from
* the supplied workflow payload.
*
* @category token
* @since 4.0.0
*/
export const tokenFromPayload = /*#__PURE__*/dual(2, (self, options) => Effect.map(options.workflow.executionId(options.payload), executionId => tokenFromExecutionId(self, {
workflow: options.workflow,
executionId
})));
/**
* Completes the durable deferred identified by a token with the supplied exit,
* encoding the result through the deferred schemas.
*
* @category combinators
* @since 4.0.0
*/
export const done = /*#__PURE__*/dual(2, /*#__PURE__*/Effect.fnUntraced(function* (self, options) {
const engine = yield* EngineTag;
const token = TokenParsed.fromString(options.token);
yield* engine.deferredDone(self, {
workflowName: token.workflowName,
executionId: token.executionId,
deferredName: token.deferredName,
exit: options.exit
});
}));
/**
* Completes the durable deferred identified by a token with a successful
* value.
*
* @category combinators
* @since 4.0.0
*/
export const succeed = /*#__PURE__*/dual(2, (self, options) => done(self, {
token: options.token,
exit: Exit.succeed(options.value)
}));
/**
* Completes the durable deferred identified by a token with a typed failure.
*
* @category combinators
* @since 4.0.0
*/
export const fail = /*#__PURE__*/dual(2, (self, options) => done(self, {
token: options.token,
exit: Exit.fail(options.error)
}));
/**
* Completes the durable deferred identified by a token with a failure cause.
*
* @category combinators
* @since 4.0.0
*/
export const failCause = /*#__PURE__*/dual(2, (self, options) => done(self, {
token: options.token,
exit: Exit.failCause(options.cause)
}));
//# sourceMappingURL=DurableDeferred.js.map

Xet Storage Details

Size:
9.01 kB
·
Xet hash:
7ab74c9706bd6bcf98a61ed34140b11bf0019850399de9b51496b49b46a63b70

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.