EdgeAIG's picture
download
raw
5.49 kB
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.