| import * as Cause from "../../Cause.js"; | |
| import * as Context from "../../Context.js"; | |
| import * as Effect from "../../Effect.js"; | |
| import * as Effectable from "../../Effectable.js"; | |
| import { dual } from "../../Function.js"; | |
| import * as Schedule from "../../Schedule.js"; | |
| import * as Schema from "../../Schema.js"; | |
| import * as DurableDeferred from "./DurableDeferred.js"; | |
| import { makeHashDigest } from "./internal/crypto.js"; | |
| import * as Workflow from "./Workflow.js"; | |
| const TypeId = "~effect/workflow/Activity"; | |
| /** | |
| * Creates a workflow activity from an effect, using the provided schemas to | |
| * encode successes and failures for durable execution. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const make = options => { | |
| const successSchema = options.success ?? Schema.Void; | |
| const errorSchema = options.error ?? Schema.Never; | |
| const successSchemaJson = Schema.toCodecJson(successSchema); | |
| const errorSchemaJson = Schema.toCodecJson(errorSchema); | |
| // oxlint-disable-next-line prefer-const | |
| let execute; | |
| const executeWithoutInterrupt = retryOnInterrupt(options.name, options.interruptRetryPolicy)(options.execute); | |
| const self = { | |
| ...Effectable.Prototype({ | |
| label: "Activity", | |
| evaluate(_) { | |
| return execute; | |
| } | |
| }), | |
| [TypeId]: TypeId, | |
| name: options.name, | |
| successSchema, | |
| errorSchema, | |
| exitSchema: Schema.Exit(successSchemaJson, errorSchemaJson, Schema.Defect()), | |
| annotations: options.annotations ?? Context.empty(), | |
| annotate(tag, value) { | |
| return make({ | |
| ...options, | |
| annotations: Context.add(self.annotations, tag, value) | |
| }); | |
| }, | |
| annotateMerge(context) { | |
| return make({ | |
| ...options, | |
| annotations: Context.merge(self.annotations, context) | |
| }); | |
| }, | |
| execute: executeWithoutInterrupt, | |
| executeEncoded: Effect.matchEffect(executeWithoutInterrupt, { | |
| onFailure: error => Effect.flatMap(Effect.orDie(Schema.encodeEffect(errorSchemaJson)(error)), Effect.fail), | |
| onSuccess: value => Effect.orDie(Schema.encodeEffect(successSchemaJson)(value)) | |
| }) | |
| }; | |
| execute = makeExecute(self); | |
| return self; | |
| }; | |
| const interruptRetryPolicy = /*#__PURE__*/Schedule.exponential(4.0, 1.5).pipe(/*#__PURE__*/Schedule.either(/*#__PURE__*/Schedule.spaced("10 seconds")), /*#__PURE__*/Schedule.either(/*#__PURE__*/Schedule.recurs(10)), /*#__PURE__*/Schedule.satisfiesInputType(), /*#__PURE__*/Schedule.while(meta => Effect.succeed(Cause.hasInterrupts(meta.input)))); | |
| const retryOnInterrupt = (name, policy = interruptRetryPolicy) => effect => effect.pipe(Effect.sandbox, Effect.retry(policy), Effect.catch(cause => { | |
| if (!Cause.hasInterrupts(cause)) return Effect.failCause(cause); | |
| return Effect.die(`Activity "${name}" interrupted and retry attempts exhausted`); | |
| })); | |
| /** | |
| * Retries an effect with `Effect.retry` while updating `CurrentAttempt` for | |
| * each attempt. | |
| * | |
| * @category error handling | |
| * @since 4.0.0 | |
| */ | |
| export const retry = /*#__PURE__*/dual(2, (effect, options) => Effect.suspend(() => { | |
| let attempt = 1; | |
| return Effect.suspend(() => Effect.provideService(effect, CurrentAttempt, attempt++)).pipe(Effect.retry(options)); | |
| })); | |
| /** | |
| * Context reference containing the current activity retry attempt, defaulting | |
| * to `1`. | |
| * | |
| * @category Attempts | |
| * @since 4.0.0 | |
| */ | |
| export const CurrentAttempt = /*#__PURE__*/Context.Reference("effect/workflow/Activity/CurrentAttempt", { | |
| defaultValue: () => 1 | |
| }); | |
| /** | |
| * Computes a deterministic activity idempotency key from the current workflow | |
| * execution ID, the supplied name, and optionally the current attempt. | |
| * | |
| * @category Idempotency | |
| * @since 4.0.0 | |
| */ | |
| export const idempotencyKey = /*#__PURE__*/Effect.fnUntraced(function* (name, options) { | |
| const instance = yield* InstanceTag; | |
| let key = `${instance.executionId}`; | |
| if (options?.includeAttempt) { | |
| const attempt = yield* CurrentAttempt; | |
| key += `-${attempt}`; | |
| } | |
| key += `-${name}`; | |
| return yield* makeHashDigest(key); | |
| }); | |
| /** | |
| * Runs a non-empty collection of activities as a durable race and returns the | |
| * first completed success or failure using unioned success and error schemas. | |
| * | |
| * @category racing | |
| * @since 4.0.0 | |
| */ | |
| export const raceAll = (name, activities) => DurableDeferred.raceAll({ | |
| name: `Activity/${name}`, | |
| success: Schema.Union(activities.map(activity => activity.successSchema)), | |
| error: Schema.Union(activities.map(activity => activity.errorSchema)), | |
| effects: activities.map(activity => activity) | |
| }); | |
| // ----------------------------------------------------------------------------- | |
| // internal | |
| // ----------------------------------------------------------------------------- | |
| const EngineTag = /*#__PURE__*/Context.Service("effect/workflow/WorkflowEngine"); | |
| const InstanceTag = /*#__PURE__*/Context.Service("effect/workflow/WorkflowEngine/WorkflowInstance"); | |
| const makeExecute = /*#__PURE__*/Effect.fnUntraced(function* (activity) { | |
| const engine = yield* EngineTag; | |
| const instance = yield* InstanceTag; | |
| const attempt = yield* CurrentAttempt; | |
| yield* Effect.annotateCurrentSpan({ | |
| executionId: instance.executionId | |
| }); | |
| const result = yield* Workflow.wrapActivityResult(engine.activityExecute(activity, attempt), _ => _._tag === "Suspended"); | |
| if (result._tag === "Suspended") { | |
| return yield* Workflow.suspend(instance); | |
| } | |
| return yield* result.exit; | |
| }, (effect, activity) => Effect.withSpan(effect, activity.name, { | |
| captureStackTrace: false | |
| })); | |
| //# sourceMappingURL=Activity.js.map |
Xet Storage Details
- Size:
- 5.49 kB
- Xet hash:
- 36f344a03853af62f15f7bf4a9d222a373ba31c7cfad2248082d67c4bc42de82
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.