1import * as Lambda from "@/AWS/Lambda";
2import * as Duration from "effect/Duration";
3import * as Effect from "effect/Effect";
4import path from "pathe";
5
6const main = path.resolve(import.meta.dirname, "durable-handler.ts");
7
8/**
9 * A three-operation durable orchestration: two checkpointed steps around a
10 * durable sleep. The sleep suspends the execution (the invocation returns
11 * PENDING) and Lambda re-invokes the function to resume, so a SUCCEEDED
12 * result proves the full checkpoint/replay round-trip:
13 * invoke #1 — step "reserve" checkpoints, wait checkpoints, suspend
14 * invoke #2 — replay memoizes "reserve", runs "price", completes
15 *
16 * A DurableFunction IS the Lambda function (wrapper of AWS.Lambda.Function):
17 * the wrapper sets `DurableConfig` at create time, disables the Function URL,
18 * self-binds the checkpoint-protocol IAM, and vendors
19 * `@aws/durable-execution-sdk-js` into the artifact automatically.
20 */
21export class DurableFlow extends Lambda.DurableFunction<DurableFlow>()(
22 "DurableFlow",
23) {}
24
25export default DurableFlow.make(
26 {
27 main,
28 executionTimeout: Duration.hours(1),
29 retentionPeriod: "1 day",
30 // Per-invocation budget (each resume is its own invocation).
31 timeout: Duration.seconds(60),
32 },
33 Effect.gen(function* () {
34 return Effect.fn(function* (input: { orderId: string }) {
35 const reserved = yield* Lambda.Durable.step(
36 "reserve",
37 Effect.succeed({ orderId: input.orderId, reserved: true }),
38 );
39 yield* Lambda.Durable.sleep("cooldown", "5 seconds");
40 const total = yield* Lambda.Durable.step(
41 "price",
42 // Non-deterministic work belongs inside a step: the checkpointed
43 // result replays identically on the resume invocation.
44 Effect.sync(() => 40 + 2),
45 );
46 return { orderId: reserved.orderId, reserved: reserved.reserved, total };
47 });
48 }),
49);