Skip to content

effect-temporalDurable Effect workflows on Temporal.

Author workflows with Effect — schemas, typed errors, composition — and run them on Temporal's retries, timers, signals, and history.

The whole idea, in one file

ts
import { Effect, Schema } from "effect";
import * as Workflow from "effect/unstable/workflow/Workflow";
import * as DurableClock from "effect/unstable/workflow/DurableClock";
import * as DurableDeferred from "effect/unstable/workflow/DurableDeferred";
import * as TypedActivity from "@springbird/effect-temporal/typed-activity";
import { WorkflowClient } from "@springbird/effect-temporal/client";

// 1. Define once: shared by the workflow bundle, the worker, and every client.
const OrderFlow = Workflow.make("orderFlow", {
  payload: { orderId: Schema.String },
  idempotencyKey: ({ orderId }) => orderId,
  success: Schema.String,
});
const Charge = TypedActivity.make("charge", {
  payload: { orderId: Schema.String },
  success: Schema.String,
});
const ManagerApproval = DurableDeferred.make("manager-approval", {
  success: Schema.String,
});

// 2. Author the body — an Effect, running durably in the Temporal sandbox.
//    (workflow bundle: engine-sandbox module)
export const orderFlow = makeTemporalWorkflow(OrderFlow, (payload) =>
  Effect.gen(function* () {
    const paid = yield* callActivity(Charge, { orderId: payload.orderId });
    yield* DurableClock.sleep({ name: "cooling-off", duration: "3 days" });
    const approver = yield* DurableDeferred.await(ManagerApproval);
    return `${paid}:approved-by:${approver}`;
  }),
);

// 3. Drive it from ordinary Node — typed success, typed failure, idempotent.
const wf = yield* WorkflowClient;
const result = yield* wf.execute(OrderFlow, { orderId: "ord_123" });
sh
pnpm add @springbird/effect-temporal   # or npm / yarn / bun