Skip to content

Durable Execution

ts
import { withDurableExecution } from "@aws/durable-execution-sdk-js";
import { executeWorkflow } from "@remoraflow/core";
import {
    createDurableExecutionEngine,
    createLambdaDurableExecutionAdapter,
} from "@remoraflow/core/execution";
import { dogEvaluationWorkflow, dogToolSet, model } from "./my-app";

export const handler = withDurableExecution(
    async (event, durableContext) => {
        const executionEngine = createDurableExecutionEngine(
            createLambdaDurableExecutionAdapter(durableContext),
        );

        const { output } = await executeWorkflow({
            workflowDefinition: dogEvaluationWorkflow,
            tools: dogToolSet,
            model,
            executionOptions: { executionEngine },
        });

        return output;
    },
);
ts
// workflow.ts — runs inside Temporal's sandboxed environment
import { proxyActivities, sleep, workflowInfo } from "@temporalio/workflow";
import type { ActivityOptions } from "@temporalio/workflow";
import { executeWorkflow } from "@remoraflow/core";
import {
    createDurableExecutionEngine,
    createTemporalDurableExecutionAdapter,
} from "@remoraflow/core/execution";
import { dogEvaluationWorkflow, dogToolSet, model } from "./my-app";

function createExecutionEngine() {
    const adapter = createTemporalDurableExecutionAdapter({
        workflowInfo,
        sleep,
        createActivities: (options) =>
            proxyActivities({
                startToCloseTimeout: options.startToCloseTimeout ?? "1 minute",
                retry: options.retry,
            } satisfies ActivityOptions),
    });
    return createDurableExecutionEngine(adapter);
}

export async function dogEvaluation() {
    const { output } = await executeWorkflow({
        workflowDefinition: dogEvaluationWorkflow,
        tools: dogToolSet,
        model,
        executionOptions: {
            executionEngine: createExecutionEngine(),
        },
    });

    return output;
}
ts
import { Inngest, NonRetriableError } from "inngest";
import { serve } from "inngest/bun";
import { executeWorkflow } from "@remoraflow/core";
import {
    createDurableExecutionEngine,
    createInngestDurableExecutionAdapter,
} from "@remoraflow/core/execution";
import { dogEvaluationWorkflow, dogToolSet, model } from "./my-app";

const inngest = new Inngest({ id: "my-app" });

const dogEvaluation = inngest.createFunction(
    {
        id: "dog-evaluation",
        retries: 3,
        triggers: [{ event: "app/dog-evaluation.start" }],
    },
    async ({ step, runId }) => {
        const executionEngine = createDurableExecutionEngine(
            createInngestDurableExecutionAdapter({ runId, step, NonRetriableError }),
        );

        const { output } = await executeWorkflow({
            workflowDefinition: dogEvaluationWorkflow,
            tools: dogToolSet,
            model,
            executionOptions: { executionEngine },
        });

        return output;
    },
);

// Serve over HTTP for the Inngest dev server / cloud to invoke
const handler = serve({ client: inngest, functions: [dogEvaluation] });
ts
import { executeWorkflow } from "@remoraflow/core";
import {
    createDurableExecutionEngine,
    type DurableExecutionAdapter,
} from "@remoraflow/core/execution";
import { dogEvaluationWorkflow, dogToolSet, model } from "./my-app";

// Implement the three-method DurableExecutionAdapter interface.
// The host owns the journal, suspend/resume, and retry logic.
function createMyAdapter(hostContext: MyHostContext): DurableExecutionAdapter {
    return {
        getExecutionInfo() {
            return { runId: hostContext.runId };
        },

        step(stepName, fn, options) {
            // Delegate to the host's step primitive. The host decides
            // whether to execute fn or replay a previously recorded result.
            return hostContext.runStep(stepName, fn, {
                timeout: options?.timeoutSeconds,
                maxAttempts: options?.maxAttempts,
            });
        },

        async sleep(seconds) {
            // Delegate to the host's durable sleep. This may end the
            // current invocation entirely; the host resumes the workflow
            // after the duration elapses.
            await hostContext.durableSleep(seconds);
        },
    };
}

// Inside the host's handler:
export async function handler(hostContext: MyHostContext) {
    const executionEngine = createDurableExecutionEngine(
        createMyAdapter(hostContext),
    );

    const { output } = await executeWorkflow({
        workflowDefinition: dogEvaluationWorkflow,
        tools: dogToolSet,
        model,
        executionOptions: { executionEngine },
    });

    return output;
}