> ## Documentation Index
> Fetch the complete documentation index at: https://openworkflow.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Workers

> Long-running processes that execute your workflows

A worker is a background process that executes your workflows. It polls the
database for new workflow runs, picks them up, and executes them step by step.
When it finishes one run, it looks for the next one.

Workers are stateless — all workflow progress is stored in the database, not
in the worker itself. This means you can stop a worker, restart it, or replace
it with a new one at any time. If a worker crashes, another worker can
seamlessly continue any in-progress workflows from the last completed step.

## Starting a Worker

The recommended way to run a worker is via the CLI:

<CodeGroup>
  ```bash npm theme={null}
  npx @openworkflow/cli worker start
  ```

  ```bash pnpm theme={null}
  pnpx @openworkflow/cli worker start
  ```

  ```bash bun theme={null}
  bunx @openworkflow/cli worker start
  ```
</CodeGroup>

This command:

1. Loads your `openworkflow.config.ts` configuration
2. Discovers workflow files in the configured directories
3. Starts polling the database for work
4. Handles graceful shutdown on SIGINT/SIGTERM

## How Workers Execute Workflows

When a worker picks up a workflow:

1. **Claim**: The worker atomically claims the workflow run from the database
2. **Load history**: The worker loads all completed step attempts
3. **Replay**: The worker executes the workflow function from the beginning
4. **Memoization**: Completed steps return cached results instantly
5. **Execute**: New steps are executed and their results are stored
6. **Complete**: The workflow status is updated to `completed` or `failed`

## Concurrency

Workers can process multiple workflow runs simultaneously. Configure concurrency
in your `openworkflow.config.ts`:

```ts theme={null}
import { backend } from "./openworkflow/client";
import { defineConfig } from "@openworkflow/cli";

export default defineConfig({
  backend,
  worker: {
    concurrency: 10, // Process up to 10 workflows at once
  },
});
```

Or via the CLI:

<CodeGroup>
  ```bash npm theme={null}
  npx @openworkflow/cli worker start --concurrency 10
  ```

  ```bash pnpm theme={null}
  pnpx @openworkflow/cli worker start --concurrency 10
  ```

  ```bash bun theme={null}
  bunx @openworkflow/cli worker start --concurrency 10
  ```
</CodeGroup>

<Note>
  Start with `concurrency: 10` and tune based on your workload and database
  capacity.
</Note>

## Heartbeats and Crash Recovery

Workers maintain their claim on workflow runs through a heartbeat mechanism:

1. When a worker claims a workflow, it sets an `availableAt` timestamp in the
   future
2. While executing, the worker periodically extends this timestamp
3. If the worker crashes, the heartbeat stops
4. The `availableAt` timestamp expires
5. Another worker can claim and resume the workflow

This ensures workflows are never stuck if a worker crashes.

## High Availability

For production, run multiple worker instances:

<CodeGroup>
  ```bash npm theme={null}
  # Terminal 1
  npx @openworkflow/cli worker start --concurrency 10
  # Terminal 2
  npx @openworkflow/cli worker start --concurrency 10
  ```

  ```bash pnpm theme={null}
  # Terminal 1
  pnpx @openworkflow/cli worker start --concurrency 10
  # Terminal 2
  pnpx @openworkflow/cli worker start --concurrency 10
  ```

  ```bash bun theme={null}
  # Terminal 1
  bunx @openworkflow/cli worker start --concurrency 10
  # Terminal 2
  bunx @openworkflow/cli worker start --concurrency 10
  ```
</CodeGroup>

Workers coordinate through the database:

* Each workflow run is claimed by exactly one worker at a time
* Workers use atomic database operations to prevent duplicate processing
* If a worker crashes, its workflows become available to other workers

## Graceful Shutdown

When a worker receives SIGINT or SIGTERM:

1. It stops polling for new work
2. It waits for active workflow runs to complete their current step
3. Active workflows are persisted back to the database
4. The worker process exits

This ensures no work is lost during deploys.

<CodeGroup>
  ```bash npm theme={null}
  # The worker handles Ctrl+C gracefully
  npx @openworkflow/cli worker start
  ^C
  # [info] Shutting down worker...
  # [info] Worker stopped
  ```

  ```bash pnpm theme={null}
  # The worker handles Ctrl+C gracefully
  pnpx @openworkflow/cli worker start
  ^C
  # [info] Shutting down worker...
  # [info] Worker stopped
  ```

  ```bash bun theme={null}
  # The worker handles Ctrl+C gracefully
  bunx @openworkflow/cli worker start
  ^C
  # [info] Shutting down worker...
  # [info] Worker stopped
  ```
</CodeGroup>

## Workflow Discovery

The CLI automatically discovers workflows from directories specified in your
config:

```ts theme={null}
// openworkflow.config.ts
export default defineConfig({
  backend,
  dirs: ["./openworkflow"], // Default directory
});
```

Workflow files should export workflows created with `defineWorkflow()`:

```ts theme={null}
// openworkflow/send-email.ts
import { defineWorkflow } from "openworkflow";

export const sendEmail = defineWorkflow(
  { name: "send-email" },
  async ({ input, step }) => {
    // ...
  },
);
```

The CLI scans for `.ts`, `.js`, `.mts`, `.mjs`, `.cts`, and `.cjs` files.
