### Define Workflow with Parameters Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workflows.mdx This example demonstrates how to define a workflow and access its parameters: input, step API, version, and run metadata. Use this to start building your workflow logic. ```typescript defineWorkflow({ name: "example" }, async ({ input, step, version, run }) => { console.log("Input:", input); console.log("Version:", version); console.log("Run ID:", run.id); await step.run({ name: "my-step" }, async () => { // step logic }); }); ``` -------------------------------- ### Install OpenWorkflow and PostgreSQL Driver Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/configuration.mdx Install the necessary packages for using the PostgreSQL backend with npm, pnpm, or bun. ```bash npm i openworkflow postgres ``` ```bash pnpm add openworkflow postgres ``` ```bash bun add openworkflow postgres ``` -------------------------------- ### Full OpenWorkflow Configuration Example Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/configuration.mdx A comprehensive example demonstrating PostgreSQL backend, multiple directories, ignore patterns, and worker concurrency. ```typescript import { defineConfig } from "@openworkflow/cli"; import { BackendPostgres } from "openworkflow/postgres"; export default defineConfig({ // PostgreSQL for production, with namespace backend: await BackendPostgres.connect( process.env.OPENWORKFLOW_POSTGRES_URL!, { namespaceId: process.env.OPENWORKFLOW_NAMESPACE_ID || "default", }, ), // Scan multiple directories dirs: ["./openworkflow", "./src/workflows"], // Ignore test files ignorePatterns: ["**/*.test.*", "**/*.spec.*"], // Worker configuration worker: { concurrency: 8, }, }); ``` -------------------------------- ### Initialize OpenWorkflow CLI Source: https://github.com/openworkflowdev/openworkflow/blob/main/README.md Commands to initialize a new OpenWorkflow project using different package managers (npm, pnpm, bun). The CLI will guide you through the setup process. ```bash # npm npx @openworkflow/cli init # pnpm pnpx @openworkflow/cli init # bun bunx @openworkflow/cli init ``` -------------------------------- ### Setup SQLite Backend Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/sqlite.mdx Import necessary classes and connect to a SQLite database file. This setup is synchronous and ideal for local development. ```typescript import { OpenWorkflow } from "openworkflow"; import { BackendSqlite } from "openworkflow/sqlite"; const backend = BackendSqlite.connect("./openworkflow/backend.db"); const ow = new OpenWorkflow({ backend }); ``` -------------------------------- ### Install OpenWorkflow CLI Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/cli.mdx Install the OpenWorkflow CLI as a development dependency using npm, pnpm, or bun. ```bash npm install -D @openworkflow/cli ``` ```bash pnpm add -D @openworkflow/cli ``` ```bash bun add -D @openworkflow/cli ``` -------------------------------- ### Start Dashboard with npm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/dashboard.mdx Starts the OpenWorkflow dashboard using npm. The dashboard will be accessible at http://localhost:3000 by default. ```bash npx @openworkflow/cli dashboard ``` -------------------------------- ### Start a Worker with Concurrency via npm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Start a worker and specify the concurrency level directly from the command line using npm. ```bash npx @openworkflow/cli worker start --concurrency 10 ``` -------------------------------- ### Start a Worker with Concurrency via bun Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Start a worker and specify the concurrency level directly from the command line using bun. ```bash bunx @openworkflow/cli worker start --concurrency 10 ``` -------------------------------- ### Run First Workflow Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/quickstart.mdx Trigger the example 'hello-world' workflow to create a new run. This script enqueues the workflow for the worker to process. ```bash npx tsx openworkflow/hello-world.run.ts ``` ```bash pnpx tsx openworkflow/hello-world.run.ts ``` ```bash bun openworkflow/hello-world.run.ts ``` -------------------------------- ### Start a Worker using npm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Use this command to start a worker process with npm. It loads configuration, discovers workflows, and begins polling for work. ```bash npx @openworkflow/cli worker start ``` -------------------------------- ### Start Dashboard with bun Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/dashboard.mdx Starts the OpenWorkflow dashboard using bun. The dashboard will be accessible at http://localhost:3000 by default. ```bash bunx @openworkflow/cli dashboard ``` -------------------------------- ### Configure PostgreSQL and SQLite Backends Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/configuration.mdx Examples of connecting to PostgreSQL for production and SQLite for development environments. ```typescript // PostgreSQL (production) backend: await BackendPostgres.connect(process.env.OPENWORKFLOW_POSTGRES_URL!), // SQLite (development) backend: BackendSqlite.connect("./openworkflow/backend.db"), ``` -------------------------------- ### Start a Worker with Concurrency via pnpm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Start a worker and specify the concurrency level directly from the command line using pnpm. ```bash pnpx @openworkflow/cli worker start --concurrency 10 ``` -------------------------------- ### Start a Worker using bun Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Use this command to start a worker process with bun. It loads configuration, discovers workflows, and begins polling for work. ```bash bunx @openworkflow/cli worker start ``` -------------------------------- ### Examples of Good vs. Bad Step Granularity Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/steps.mdx Illustrates the difference between well-defined steps representing single logical operations and steps that are too granular or too coarse. Use these examples to guide your step definition for optimal workflow management. ```typescript // Good - each step is a meaningful operation await step.run({ name: "fetch-user" }, ...); await step.run({ name: "validate-subscription" }, ...); await step.run({ name: "charge-payment" }, ...); await step.run({ name: "send-receipt" }, ...); ``` ```typescript // Too granular - overhead outweighs benefits await step.run({ name: "parse-json" }, ...); await step.run({ name: "validate-field-1" }, ...); await step.run({ name: "validate-field-2" }, ...); ``` ```typescript // Too coarse - no benefit from checkpointing await step.run({ name: "do-everything" }, async () => { await fetchUser(); await chargeCard(); await sendEmail(); }); ``` -------------------------------- ### Install PostgreSQL Driver (bun) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx If using PostgreSQL, install the 'postgres' driver directly using bun after removing legacy packages. This is required for v0.6. ```bash bun add postgres ``` -------------------------------- ### Load Environment Variables from .env File Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/configuration.mdx Example of how environment variables like database URLs and namespace IDs can be loaded from a .env file. ```bash # .env OPENWORKFLOW_POSTGRES_URL=postgresql://user:pass@localhost:5432/openworkflow OPENWORKFLOW_NAMESPACE_ID=development ``` -------------------------------- ### Start a Worker using pnpm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Use this command to start a worker process with pnpm. It loads configuration, discovers workflows, and begins polling for work. ```bash pnpx @openworkflow/cli worker start ``` -------------------------------- ### Start OpenWorkflow Dashboard Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/cli.mdx Start the web dashboard for OpenWorkflow. By default, it runs on http://localhost:3000. ```bash npx @openworkflow/cli dashboard ``` ```bash pnpx @openworkflow/cli dashboard ``` ```bash bunx @openworkflow/cli dashboard ``` -------------------------------- ### Start Dashboard with pnpm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/dashboard.mdx Starts the OpenWorkflow dashboard using pnpm. The dashboard will be accessible at http://localhost:3000 by default. ```bash pnpx @openworkflow/cli dashboard ``` -------------------------------- ### Initialize OpenWorkflow Project Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/cli.mdx Initialize OpenWorkflow in your project. This interactive command sets up the configuration file, example workflow, and package.json scripts. ```bash npx @openworkflow/cli init ``` ```bash pnpx @openworkflow/cli init ``` ```bash bunx @openworkflow/cli init ``` -------------------------------- ### Run Parallel Child Workflows Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/child-workflows.mdx Start multiple child workflows concurrently using `Promise.all`. This example runs payment and shipping workflows in parallel for an order. ```typescript const [payment, shipping] = await Promise.all([ step.runWorkflow(paymentWorkflow.spec, { orderId: input.orderId, }), step.runWorkflow(shippingWorkflow.spec, { orderId: input.orderId, }), ]); ``` -------------------------------- ### Dockerfile for Node.js Worker (bun) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/production.mdx A Dockerfile template for deploying an OpenWorkflow worker using bun. It installs dependencies with bun, copies project files, and sets the command to start the worker. ```dockerfile FROM oven/bun:1 WORKDIR /app COPY package.json bun.lock ./ RUN bun install --frozen-lockfile COPY . . CMD ["bunx", "@openworkflow/cli", "worker", "start"] ``` -------------------------------- ### Start Dashboard on Custom Port with bun Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/dashboard.mdx Starts the OpenWorkflow dashboard on a custom port (e.g., 4000) using bun. ```bash bunx @openworkflow/cli dashboard --port 4000 ``` -------------------------------- ### Start Dashboard on Custom Port with npm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/dashboard.mdx Starts the OpenWorkflow dashboard on a custom port (e.g., 4000) using npm. ```bash npx @openworkflow/cli dashboard --port 4000 ``` -------------------------------- ### Dockerfile for Node.js Worker (npm) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/production.mdx A Dockerfile template for deploying an OpenWorkflow worker using npm. It installs dependencies, copies project files, and sets the command to start the worker. ```dockerfile FROM node:22-slim WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY . . CMD ["npx", "@openworkflow/cli", "worker", "start"] ``` -------------------------------- ### Start Dashboard on Custom Port Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/cli.mdx Start the OpenWorkflow dashboard on a custom port by specifying the --port option. ```bash npx @openworkflow/cli dashboard --port 4000 ``` ```bash pnpx @openworkflow/cli dashboard --port 4000 ``` ```bash bunx @openworkflow/cli dashboard --port 4000 ``` -------------------------------- ### Install PostgreSQL Driver (npm) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx If using PostgreSQL, install the 'postgres' driver directly using npm after removing legacy packages. This is required for v0.6. ```bash npm install postgres ``` -------------------------------- ### Start Dashboard on Custom Port with pnpm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/dashboard.mdx Starts the OpenWorkflow dashboard on a custom port (e.g., 4000) using pnpm. ```bash pnpx @openworkflow/cli dashboard --port 4000 ``` -------------------------------- ### Install PostgreSQL Driver (pnpm) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx If using PostgreSQL, install the 'postgres' driver directly using pnpm after removing legacy packages. This is required for v0.6. ```bash pnpm add postgres ``` -------------------------------- ### Configure Workflow Directories Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/configuration.mdx Examples of specifying a single directory or multiple directories for OpenWorkflow to scan for workflow files. ```typescript // Single directory dirs: "./openworkflow", // Multiple directories dirs: ["./openworkflow", "./src/workflows"], ``` -------------------------------- ### Show CLI Version Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/cli.mdx Display the installed version of the OpenWorkflow CLI. ```bash npx @openworkflow/cli --version ``` ```bash pnpx @openworkflow/cli --version ``` ```bash bunx @openworkflow/cli --version ``` -------------------------------- ### Get Backend for Tenant ID Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/namespaces.mdx Demonstrates how to dynamically create a backend connection for a specific tenant by prefixing the tenant ID to the namespace. This is useful for multi-tenancy. ```typescript async function getBackendForTenant(tenantId: string) { return BackendPostgres.connect(process.env.OPENWORKFLOW_POSTGRES_URL!, { namespaceId: `tenant-${tenantId}`, }); } ``` -------------------------------- ### Run a Workflow Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workflows.mdx Start a workflow execution using `ow.runWorkflow` with the workflow's spec and input. This returns a handle immediately, with execution happening in a worker process. ```typescript import { ow } from "./openworkflow/client"; import { sendWelcomeEmail } from "./workflows/send-welcome-email"; const handle = await ow.runWorkflow(sendWelcomeEmail.spec, { userId: "user_123", }); ``` -------------------------------- ### Specify Configuration File Path Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/configuration.mdx How to start the OpenWorkflow worker with an explicitly defined configuration file path. ```bash npx @openworkflow/cli worker start --config src/openworkflow.config.ts ``` -------------------------------- ### Conditional Backend Setup for Dev/Prod Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/sqlite.mdx Dynamically choose between SQLite for development and PostgreSQL for production based on the `NODE_ENV` environment variable. Ensure PostgreSQL connection URL is provided in production. ```typescript import { defineConfig } from "@openworkflow/cli"; import { BackendPostgres } from "openworkflow/postgres"; import { BackendSqlite } from "openworkflow/sqlite"; const isDev = process.env.NODE_ENV !== "production"; const backend = isDev ? BackendSqlite.connect("./openworkflow/backend.db") : await BackendPostgres.connect(process.env.OPENWORKFLOW_POSTGRES_URL!); export default defineConfig({ backend, dirs: ["./openworkflow"], }); ``` -------------------------------- ### Worker Replay Loop Example Source: https://github.com/openworkflowdev/openworkflow/blob/main/ARCHITECTURE.md Demonstrates how a worker claims a workflow run, replays completed steps from history, and executes new steps. ```typescript const user = await step.run({ name: "fetch-user" }, async () => { // 1. The framework sees "fetch-user". // 2. It finds a completed result in the history. // 3. It returns the cached output immediately without executing the function. return await db.users.findOne({ id: 1 }); }); const welcomeEmail = await step.run({ name: "welcome-email" }, async () => { // 4. The framework sees "welcome-email". // 5. It is NOT in the history. // 6. It creates a step_attempt with status "running". // 7. It executes the function and saves the result. // 8. It updates the step_attempt to status "completed" and continues. return await email.send(user); }); ``` -------------------------------- ### Start OpenWorkflow Worker Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/cli.mdx Start a worker to process workflows. This command loads configuration, discovers workflows, and begins polling for work. ```bash npx @openworkflow/cli worker start ``` ```bash pnpx @openworkflow/cli worker start ``` ```bash bunx @openworkflow/cli worker start ``` -------------------------------- ### Workflow with Steps for Safe Operations Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/steps.mdx This example demonstrates how to use steps to ensure operations like charging a credit card and sending an email are not accidentally repeated if the workflow crashes. Each operation is wrapped in `step.run()`. ```typescript defineWorkflow({ name: "process-order" }, async ({ input, step }) => { await step.run({ name: "charge-card" }, async () => { await chargeCard(input.orderId); }); await step.run({ name: "send-email" }, async () => { await sendConfirmationEmail(input.orderId); }); }); ``` -------------------------------- ### Basic Workflow Sleep Example Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/sleeping.mdx Demonstrates how to pause a workflow for 7 days using `step.sleep()`. Ensure `emailService` is properly configured and imported. ```typescript import { defineWorkflow } from "openworkflow"; export const reminderWorkflow = defineWorkflow( { name: "send-reminder" }, async ({ input, step }) => { await step.run({ name: "send-initial-email" }, async () => { await emailService.send({ to: input.email, subject: "Welcome!", }); }); // Pause for 7 days await step.sleep("wait-7-days", "7d"); await step.run({ name: "send-followup" }, async () => { await emailService.send({ to: input.email, subject: "How's it going?", }); }); }, ); ``` -------------------------------- ### OpenWorkflow Durable Workflow Example Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/openworkflow-vs-bullmq.mdx Demonstrates how to define a multi-step process as a single function in OpenWorkflow, which handles durable step history and replay. ```typescript import { workflow, step } from "openworkflow"; export const sendWelcomeEmail = workflow({ id: "send-welcome-email", version: "1.0.0", steps: { sendEmail: step({ handler: async ({ input }) => { // ... send email logic ... return { emailSent: true }; }, }), logToDatabase: step({ dependsOn: "sendEmail", handler: async ({ output }) => { // ... log email status to DB ... return { logged: true }; }, }), }, }); ``` -------------------------------- ### Start Child Workflow with `step.runWorkflow()` Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/steps.mdx Use `step.runWorkflow()` to initiate a child workflow and await its durable result. Pass the child workflow's spec, input, and optional configuration like timeout. ```typescript const childOutput = await step.runWorkflow( generateReportWorkflow.spec, { reportId: input.reportId }, { timeout: "5m" }, // optional, defaults to 1 year ); ``` -------------------------------- ### Define a Workflow Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Example of defining a workflow using 'defineWorkflow'. Workflows are exported from files in the configured discovery directories. ```typescript // openworkflow/send-email.ts import { defineWorkflow } from "openworkflow"; export const sendEmail = defineWorkflow( { name: "send-email" }, async ({ input, step }) => { // ... }, ); ``` -------------------------------- ### Updated package.json Dependencies Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx Example of a package.json file after upgrading to OpenWorkflow v0.6, including the core package and the 'postgres' driver if applicable. ```json { "dependencies": { "openworkflow": "^0.6.0", "postgres": "^3.4.8" // Only if using PostgreSQL } } ``` -------------------------------- ### Start Worker with Custom Concurrency Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/cli.mdx Run the worker with a specified number of concurrent workflow executions, overriding the configuration setting. ```bash # Run with 4 concurrent workflows npx @openworkflow/cli worker start --concurrency 4 ``` ```bash # Run with 4 concurrent workflows pnpx @openworkflow/cli worker start --concurrency 4 ``` ```bash # Run with 4 concurrent workflows bunx @openworkflow/cli worker start --concurrency 4 ``` -------------------------------- ### Configure Step Retry Policy Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/retries.mdx This example shows how to override the default retry policy for a specific step. You can customize the initial interval, backoff coefficient, maximum interval, and maximum attempts. ```typescript await step.run( { name: "call-api", retryPolicy: { initialInterval: "500ms", backoffCoefficient: 2, maximumInterval: "30s", maximumAttempts: 5, }, }, async () => { // step logic }, ); ``` -------------------------------- ### Uninstall Legacy Backend Packages (bun) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx Remove the old backend packages using bun before upgrading to v0.6. This ensures a clean installation of the new core package. ```bash bun remove @openworkflow/backend-postgres @openworkflow/backend-sqlite ``` -------------------------------- ### Define a Durable Workflow with Checkpointed Steps Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/snippets/comparison-durable-workflow.mdx This example demonstrates how to define a durable workflow using `defineWorkflow`. Each `step.run` call represents a durable checkpoint. If the workflow crashes, it will resume from the last completed step. ```typescript import { defineWorkflow } from "openworkflow"; export const processOrder = defineWorkflow( { name: "process-order" }, async ({ input, step }) => { // validate the order, charge the payment, and fulfill the order const order = await step.run({ name: "validate-order" }, async () => { return await orders.validate(input.orderId); }); await step.run({ name: "charge-payment" }, async () => { await payments.charge(order.paymentMethod, order.total); }); await step.run({ name: "fulfill-order" }, async () => { await warehouse.ship(order.id, order.shippingAddress); }); // wait 7 days for delivery, then ask for a review await step.sleep("wait-for-delivery", "7d"); await step.run({ name: "request-review" }, async () => { await email.send({ to: order.email, template: "review-request" }); }); }, ); ``` -------------------------------- ### Parallel Steps Crash Recovery Example Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/parallel-steps.mdx Demonstrates how parallel steps recover from worker crashes. In-progress steps are re-executed by a new worker, while completed steps return cached results. ```typescript const [a, b, c] = await Promise.all([ step.run({ name: "step-a" }, ...), // Completed before crash - cached step.run({ name: "step-b" }, ...), // Completed before crash - cached step.run({ name: "step-c" }, ...), // In progress during crash - re-runs ]); ``` -------------------------------- ### Define and Run Child Workflows Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/child-workflows.mdx Defines a `generate-report` workflow and a `process-order` workflow that calls `generate-report` as a child. Use `step.runWorkflow()` to start a child and wait for its output. ```typescript import { defineWorkflow } from "openworkflow"; const generateReport = defineWorkflow( { name: "generate-report" }, async ({ input, step }) => { const data = await step.run({ name: "fetch-data" }, async () => { return await db.reports.getData(input.reportId); }); await step.run({ name: "upload-report" }, async () => { await storage.upload(`reports/${input.reportId}.pdf`, data); }); return { reportUrl: `https://example.com/reports/${input.reportId}.pdf` }; }, ); const processOrder = defineWorkflow( { name: "process-order" }, async ({ input, step }) => { await step.run({ name: "charge-card" }, async () => { await payments.charge(input.orderId); }); // Start the report workflow and wait for it to finish const report = await step.runWorkflow(generateReport.spec, { reportId: input.orderId, }); await step.run({ name: "send-confirmation" }, async () => { await email.send({ to: input.email, subject: "Order complete", body: `Your report is ready: ${report.reportUrl}`, }); }); }, ); ``` -------------------------------- ### Uninstall Legacy Backend Packages (pnpm) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx Remove the old backend packages using pnpm before upgrading to v0.6. This ensures a clean installation of the new core package. ```bash pnpm remove @openworkflow/backend-postgres @openworkflow/backend-sqlite ``` -------------------------------- ### Graceful Shutdown Example with npm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Observe the graceful shutdown process when a worker receives a SIGINT signal (Ctrl+C). The worker stops polling for new work and waits for active workflows to complete. ```bash # The worker handles Ctrl+C gracefully npx @openworkflow/cli worker start ^C # [info] Shutting down worker... # [info] Worker stopped ``` -------------------------------- ### Uninstall Legacy Backend Packages (npm) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx Remove the old backend packages using npm before upgrading to v0.6. This ensures a clean installation of the new core package. ```bash npm uninstall @openworkflow/backend-postgres @openworkflow/backend-sqlite ``` -------------------------------- ### Initialize New Project with v0.6 CLI (bun) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx Use the OpenWorkflow CLI with bun to initialize a new project. The CLI automatically generates code with the updated v0.6 import paths. ```bash bunx @openworkflow/cli init ``` -------------------------------- ### Graceful Shutdown Example with pnpm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Observe the graceful shutdown process when a worker receives a SIGINT signal (Ctrl+C). The worker stops polling for new work and waits for active workflows to complete. ```bash # The worker handles Ctrl+C gracefully pnpx @openworkflow/cli worker start ^C # [info] Shutting down worker... # [info] Worker stopped ``` -------------------------------- ### Dockerfile for Node.js Worker (pnpm) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/production.mdx A Dockerfile template for deploying an OpenWorkflow worker using pnpm. It enables corepack, installs dependencies with pnpm, copies project files, and sets the command to start the worker. ```dockerfile FROM node:22-slim RUN corepack enable WORKDIR /app COPY package.json pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile COPY . . CMD ["pnpx", "@openworkflow/cli", "worker", "start"] ``` -------------------------------- ### Initialize New Project with v0.6 CLI (pnpm) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx Use the OpenWorkflow CLI with pnpm to initialize a new project. The CLI automatically generates code with the updated v0.6 import paths. ```bash pnpx @openworkflow/cli init ``` -------------------------------- ### Initialize New Project with v0.6 CLI (npm) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx Use the OpenWorkflow CLI with npm to initialize a new project. The CLI automatically generates code with the updated v0.6 import paths. ```bash npx @openworkflow/cli init ``` -------------------------------- ### Show Help for CLI Commands Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/cli.mdx Display help information for the OpenWorkflow CLI or specific commands. ```bash npx @openworkflow/cli --help npx @openworkflow/cli worker --help npx @openworkflow/cli worker start --help ``` ```bash pnpx @openworkflow/cli --help pnpx @openworkflow/cli worker --help pnpx @openworkflow/cli worker start --help ``` ```bash bunx @openworkflow/cli --help bunx @openworkflow/cli worker --help bunx @openworkflow/cli worker start --help ``` -------------------------------- ### Return Object from Step Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/steps.mdx Steps can return complex JSON-serializable objects. This example shows returning a user object fetched from a database. ```typescript const user = await step.run({ name: "fetch-user" }, async () => { return await db.users.findOne({ id: input.userId }); }); ``` -------------------------------- ### Configure SQLite Backend Options Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/sqlite.mdx Configure the SQLite backend with options like namespace isolation and automatic migration execution. Defaults are provided for convenience. ```typescript const backend = BackendSqlite.connect(path, { // Namespace for multi-tenant isolation (default: "default") namespaceId: "development", // Whether to run migrations on connect (default: true) runMigrations: true, }); ``` -------------------------------- ### Run Steps Concurrently with Promise.all Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/advanced-patterns.mdx Use `Promise.all` to execute multiple steps concurrently. Each step is memoized individually, and completed steps return instantly on resume if the workflow crashes mid-execution. ```typescript const [user, subscription, settings] = await Promise.all([ step.run({ name: "fetch-user" }, async () => { await db.users.findOne({ id: input.userId }); }), step.run({ name: "fetch-subscription" }, async () => { await stripe.subscriptions.retrieve(input.subId); }), step.run({ name: "fetch-settings" }, async () => { await db.settings.findOne({ userId: input.userId }); }), ]); ``` -------------------------------- ### Return Primitive from Step Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/steps.mdx Steps can return simple JSON-serializable primitive values like numbers. This example returns the length of an items array. ```typescript const count = await step.run({ name: "count-items" }, async () => { return items.length; }); ``` -------------------------------- ### Connect to Production and Staging Namespaces Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/namespaces.mdx Demonstrates connecting to separate production and staging namespaces using the same database. Specify the `namespaceId` option during connection. ```typescript import { BackendPostgres } from "openworkflow/postgres"; // Production namespace const prodBackend = await BackendPostgres.connect(url, { namespaceId: "production", }); // Staging namespace (same database) const stagingBackend = await BackendPostgres.connect(url, { namespaceId: "staging", }); ``` -------------------------------- ### Configure PostgreSQL Backend Options Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/postgres.mdx Customize the PostgreSQL backend connection with options like namespaceId, schema, and migration settings. ```typescript const backend = await BackendPostgres.connect(url, { // Namespace for multi-tenant isolation (default: "default") namespaceId: "production", // Database schema for OpenWorkflow tables (default: "openworkflow") schema: "openworkflow", // Whether to run migrations on connect (default: true) runMigrations: true, }); ``` -------------------------------- ### Define a Workflow with Steps Source: https://github.com/openworkflowdev/openworkflow/blob/main/packages/openworkflow/README.md Defines a workflow named 'send-welcome-email' that fetches user data, sends an email, and updates user status. Use this to structure sequential or parallel tasks within a workflow. ```typescript import { defineWorkflow } from "openworkflow"; export const sendWelcomeEmail = defineWorkflow( { name: "send-welcome-email" }, async ({ input, step }) => { const user = await step.run({ name: "fetch-user" }, async () => { return await db.users.findOne({ id: input.userId }); }); await step.run({ name: "send-email" }, async () => { return await resend.emails.send({ from: "me@example.com", to: user.email, replyTo: "me@example.com", subject: "Welcome!", html: "

Welcome to our app!

", }); }); await step.run({ name: "mark-welcome-email-sent" }, async () => { await db.users.update(input.userId, { welcomeEmailSent: true }); }); return { user }; }, ); ``` -------------------------------- ### Verify Upgrade with Doctor Command (bun) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx Run the OpenWorkflow doctor command using bun to verify that the migration to v0.6 was successful. Expect a 'Configuration looks good!' message. ```bash bunx @openworkflow/cli doctor ``` -------------------------------- ### Disable Automatic PostgreSQL Migrations Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/postgres.mdx Disable automatic database migrations on connection by setting `runMigrations` to `false`. Ensure migrations are run manually before starting workers. ```typescript const backend = await BackendPostgres.connect(url, { runMigrations: false, }); ``` -------------------------------- ### Return Null or Undefined from Step Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/steps.mdx Steps can implicitly or explicitly return undefined, which is stored as null in the workflow history. This example logs an event and returns undefined. ```typescript await step.run({ name: "log-event" }, async () => { console.log("Event logged"); // implicitly returns undefined, stored as null }); ``` -------------------------------- ### Handle Child Workflow Failures Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/child-workflows.mdx Implement error handling for child workflows within the parent. This example catches errors from `step.runWorkflow` and notifies about payment failures. ```typescript const orderPipeline = defineWorkflow( { name: "order-pipeline" }, async ({ input, step }) => { try { const result = await step.runWorkflow(chargeWorkflow.spec, { orderId: input.orderId, }); return result; } catch (error) { // Handle child failure in the parent await step.run({ name: "notify-failure" }, async () => { await alerts.send(`Payment failed for order ${input.orderId}`); }); } }, ); ``` -------------------------------- ### Basic OpenWorkflow Configuration Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/configuration.mdx A basic configuration file for OpenWorkflow using PostgreSQL as the backend and specifying workflow directories. ```typescript import { defineConfig } from "@openworkflow/cli"; import { BackendPostgres } from "openworkflow/postgres"; export default defineConfig({ backend: await BackendPostgres.connect( process.env.OPENWORKFLOW_POSTGRES_URL!, ), dirs: ["./openworkflow"], }); ``` -------------------------------- ### Define a Basic Workflow Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/index.mdx Define a simple workflow named 'process-order' that charges a card and sends a confirmation email. Completed steps are not re-run if the process crashes. ```typescript import { defineWorkflow } from "openworkflow"; export const processOrder = defineWorkflow( { name: "process-order" }, async ({ input, step }) => { // if the server crashes after this step, the card is NOT charged again await step.run({ name: "charge-card" }, async () => { await payments.charge(input.orderId); }); await step.run({ name: "send-confirmation" }, async () => { await emails.send({ to: input.email, subject: "Order confirmed!" }); }); }, ); ``` -------------------------------- ### Connect to SQLite Namespace Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/namespaces.mdx Illustrates connecting to a SQLite backend with a specified namespace ID. Namespaces function similarly across different backend types. ```typescript import { BackendSqlite } from "openworkflow/sqlite"; const backend = BackendSqlite.connect("./backend.db", { namespaceId: "development", }); ``` -------------------------------- ### Parallel Steps Error Handling with Promise.allSettled Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/parallel-steps.mdx Shows how to use Promise.allSettled to get results from all parallel steps, regardless of success or failure. This is useful when you need to process all outcomes. ```typescript const results = await Promise.allSettled([ step.run({ name: "fetch-user" }, ...), step.run({ name: "fetch-settings" }, ...), ]); for (const result of results) { if (result.status === "fulfilled") { console.log("Success:", result.value); } else { console.log("Failed:", result.reason); } } ``` -------------------------------- ### Cancel a Running Workflow Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/advanced-patterns.mdx Cancel a workflow that is pending or currently running to stop its execution. Canceled workflows will not start new steps, though currently executing steps will finish. ```typescript const handle = await ow.runWorkflow(myWorkflow.spec, { data: "..." }); // Cancel the workflow await handle.cancel(); ``` -------------------------------- ### Set Timeout for Child Workflow Execution Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/child-workflows.mdx Customize the maximum wait time for a child workflow to complete using the `options.timeout` parameter. This example sets a timeout of 5 minutes. ```typescript const result = await step.runWorkflow( quickTaskWorkflow.spec, { taskId: "abc" }, { timeout: "5m" }, // wait at most 5 minutes ); ``` -------------------------------- ### Verify Metrics Endpoint Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/prometheus.mdx Fetch the metrics from the dashboard's /metrics endpoint to verify it's running and serving data. ```bash curl -s http://localhost:3000/metrics ``` -------------------------------- ### Verify Upgrade with Doctor Command (npm) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx Run the OpenWorkflow doctor command using npm to verify that the migration to v0.6 was successful. Expect a 'Configuration looks good!' message. ```bash npx @openworkflow/cli doctor ``` -------------------------------- ### Graceful Shutdown Example with bun Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Observe the graceful shutdown process when a worker receives a SIGINT signal (Ctrl+C). The worker stops polling for new work and waits for active workflows to complete. ```bash # The worker handles Ctrl+C gracefully bunx @openworkflow/cli worker start ^C # [info] Shutting down worker... # [info] Worker stopped ``` -------------------------------- ### Define a Workflow with Steps Source: https://github.com/openworkflowdev/openworkflow/blob/main/README.md This snippet defines a 'sendWelcomeEmail' workflow using 'defineWorkflow'. It includes steps to fetch user data, send an email, and update user status. Ensure 'db' and 'resend' are properly configured. ```typescript import { defineWorkflow } from "openworkflow"; export const sendWelcomeEmail = defineWorkflow( { name: "send-welcome-email" }, async ({ input, step }) => { const user = await step.run({ name: "fetch-user" }, async () => { return await db.users.findOne({ id: input.userId }); }); await step.run({ name: "send-email" }, async () => { return await resend.emails.send({ from: "me@example.com", to: user.email, replyTo: "me@example.com", subject: "Welcome!", html: "

Welcome to our app!

", }); }); await step.run({ name: "mark-welcome-email-sent" }, async () => { await db.users.update(input.userId, { welcomeEmailSent: true }); }); return { user }; }, ); ``` -------------------------------- ### Connect to PostgreSQL Backend Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/postgres.mdx Connect to the PostgreSQL backend using the connection URL. Ensure the OPENWORKFLOW_POSTGRES_URL environment variable is set. ```typescript import { OpenWorkflow } from "openworkflow"; import { BackendPostgres } from "openworkflow/postgres"; const backend = await BackendPostgres.connect( process.env.OPENWORKFLOW_POSTGRES_URL, // e.g., "postgresql://user:pass@localhost:5432/mydb" ); const ow = new OpenWorkflow({ backend }); ``` -------------------------------- ### Set Worker Concurrency Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/production.mdx Configure the maximum number of workflows a single worker can process simultaneously. Start with 10 and adjust based on workflow type (I/O-bound vs. CPU-bound) and database connection limits. ```typescript worker: { concurrency: 10, // Process up to 10 workflows at once } ``` -------------------------------- ### Deterministic vs. Non-Deterministic Workflows Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workflows.mdx Illustrates how to write deterministic workflows by wrapping non-deterministic operations in steps. Avoid calling functions like Math.random() or Date.now() directly within the workflow body. ```typescript // Bad - non-deterministic defineWorkflow({ name: "bad" }, async ({ step }) => { const random = Math.random(); // Different on replay! // ... }); // Good - deterministic defineWorkflow({ name: "good" }, async ({ step }) => { const random = await step.run({ name: "get-random" }, () => Math.random()); // ... }); ``` -------------------------------- ### Verify Upgrade with Doctor Command (pnpm) Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/migration-v6.mdx Run the OpenWorkflow doctor command using pnpm to verify that the migration to v0.6 was successful. Expect a 'Configuration looks good!' message. ```bash pnpx @openworkflow/cli doctor ``` -------------------------------- ### Fan-Out Signal Delivery Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/signals.mdx A single `sendSignal` call can deliver to all workflows currently waiting for that specific signal name, enabling straightforward fan-out coordination. This example shows two workflows waiting for the same 'config-updated' signal. ```typescript // Multiple workflows waiting on the same signal const workflowA = defineWorkflow({ name: "listener-a" }, async ({ step }) => { const config = await step.waitForSignal({ signal: "config-updated" }); // handle update }); const workflowB = defineWorkflow({ name: "listener-b" }, async ({ step }) => { const config = await step.waitForSignal({ signal: "config-updated" }); // handle update }); // One signal wakes both workflows await ow.sendSignal({ signal: "config-updated", data: { version: 42 }, }); ``` -------------------------------- ### Pre-1.0 Versioning Convention Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/releases.mdx Illustrates the versioning scheme for pre-1.0 releases where minor version bumps indicate breaking changes, while patch versions are for safe bug fixes or new features. This convention helps users understand the risk associated with upgrades. ```text 0.9.0 → 0.9.1 safe bug fix or new feature 0.9.1 → 0.9.2 safe bug fix or new feature 0.9.2 → 0.10.0 break read the changelog before you upgrade ``` -------------------------------- ### Set Namespace via Environment Variable for Worker Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/namespaces.mdx Provides examples of setting the `OPENWORKFLOW_NAMESPACE_ID` environment variable for different package managers (npm, pnpm, bun) to run workers in specific namespaces (development, staging, production). ```bash # Development OPENWORKFLOW_NAMESPACE_ID=development npm run worker # Staging OPENWORKFLOW_NAMESPACE_ID=staging npm run worker # Production OPENWORKFLOW_NAMESPACE_ID=production npm run worker ``` ```bash # Development OPENWORKFLOW_NAMESPACE_ID=development pnpm run worker # Staging OPENWORKFLOW_NAMESPACE_ID=staging pnpm run worker # Production OPENWORKFLOW_NAMESPACE_ID=production pnpm run worker ``` ```bash # Development OPENWORKFLOW_NAMESPACE_ID=development bun run worker # Staging OPENWORKFLOW_NAMESPACE_ID=staging bun run worker # Production OPENWORKFLOW_NAMESPACE_ID=production bun run worker ``` -------------------------------- ### Connect to Test Namespace Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/namespaces.mdx Shows how to establish a backend connection to a unique, dynamically generated namespace for test runs. This helps isolate test data. ```typescript // In your test setup const testNamespace = `test-${Date.now()}`; const backend = await BackendPostgres.connect(testUrl, { namespaceId: testNamespace, }); ``` -------------------------------- ### Run Multiple High Availability Workers with npm Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/workers.mdx Deploy multiple worker instances to ensure high availability. Each worker coordinates through the database to claim and process workflow runs. ```bash # Terminal 1 npx @openworkflow/cli worker start --concurrency 10 # Terminal 2 npx @openworkflow/cli worker start --concurrency 10 ``` -------------------------------- ### Configure PostgreSQL Connection Source: https://github.com/openworkflowdev/openworkflow/blob/main/apps/docs/docs/cli.mdx Set the PostgreSQL connection URL in the .env file for the OpenWorkflow CLI. ```bash # .env OPENWORKFLOW_POSTGRES_URL=postgresql://user:pass@localhost:5432/openworkflow ```