/ Docs

Process Managers

What is a Process Manager?

A process manager orchestrates a multi-step workflow that spans multiple events over time. Unlike a policy, which reacts to a single event, a process manager tracks state across a sequence of events, coordinating actions until the workflow completes, times out, or fails.

Process Managers in Bounda

Process managers live inside domain/<aggregate>/processes/<process-name>/ as a folder containing a configuration file and individual event handler files.

domain/
  order/
    processes/
      order-lifecycle/
        index.ts
        on-order-placed.ts
        on-payment-received.ts
        on-order-fulfilled.ts
        on-order-lifecycle-timed-out.ts

Configuration

The index.ts file exports a config function that defines when the process starts, when it completes, and an optional timeout:

import type { ProcessManager } from "./+types/order-lifecycle";

export const config: ProcessManager.ConfigFunction = ({ events }) => ({
  startedBy: [events.OrderPlaced],
  completedBy: [events.OrderFulfilled],
  timeout: "7d",
});

Configuration Options

OptionDescription
startedByArray of event types that create a new process instance
completedByArray of event types that mark the process as complete
timeoutDuration after which the process is considered timed out (e.g., "7d", "24h")

Event Handlers

Each event the process reacts to gets its own file named on-<event-name>.ts. The handler receives the event and a commands object for dispatching further actions:

import type { ProcessManager } from "./+types/on-order-placed";

export async function handler({ event, commands }: ProcessManager.HandlerArgs) {
  await commands.sendWelcomeEmail({
    aggregateId: event.aggregateId,
    delay: "1m",
  });
}

Handlers can dispatch commands immediately or with a delay using the delay property. See Scheduled Commands for supported delay formats.

Special Event Handlers

Process managers support two special handler files for lifecycle edge cases:

Timeout Handler

When a process exceeds its configured timeout, Bounda triggers the timeout handler:

import type { ProcessManager } from "./+types/on-order-lifecycle-timed-out";

export async function handler({ event, commands }: ProcessManager.HandlerArgs) {
  await commands.cancelOrder({
    aggregateId: event.aggregateId,
  });
}

The file is named on-<process-name>-timed-out.ts.

Failure Handler

When a step in the process fails after exhausting retries, the failure handler is triggered:

import type { ProcessManager } from "./+types/on-order-lifecycle-failed";

export async function handler({ event, commands }: ProcessManager.HandlerArgs) {
  await commands.flagForManualReview({
    aggregateId: event.aggregateId,
  });
}

The file is named on-<process-name>-failed.ts.

Process State

Bounda tracks process manager instances internally. Each instance records:

FieldDescription
processIdUnique identifier for the process instance
statusCurrent status: started, completed, timed_out, failed
startedAtTimestamp when the process was initiated
aggregateIdThe aggregate instance this process is associated with

Dead Letter Queue

Like policies, process managers support DLQ configuration for handlers that fail after retrying:

processes: {
  retry: {
    retryStrategy: "exponential",
    maxRetries: 3,
  },
  dlq: {
    type: "sqlite",
    path: "./db/processes-dlq.db",
  },
}

Guidelines

  • Use process managers when a workflow involves waiting for multiple events across time. For single event reactions, prefer policies.
  • Always define a timeout. Processes that never complete consume resources and obscure system state.
  • Include both timeout and failure handlers to ensure the system can recover gracefully from edge cases.
  • Process managers should coordinate, not compute. Keep business logic in commands and let the process manager orchestrate the sequence.
  • Policies — for single-event reactions without state tracking
  • Scheduled Commands — delaying command execution from process handlers
  • Commands — process handlers dispatch commands to perform actions