How to Observe the Execution of Medusa Workflows: 4 Monitoring Methods

You can observe Medusa workflow execution by subscribing to lifecycle events emitted through the WorkflowOrchestratorService, which broadcasts via Redis Pub/Sub, in-process callbacks, and REST APIs consumed by the Admin UI.

Medusa workflows handle complex, multi-step commerce operations through a durable execution engine powered by the workflow orchestrator in the @medusajs/workflow-engine-redis module. Each workflow run instantiates a DistributedTransaction that emits granular events—onBegin, onStepBegin, onStepSuccess, onStepFailure, and onFinish—enabling real-time observability. This article explores four concrete methods to monitor these executions based on the implementation in the medusajs/medusa repository.

Understanding the Workflow Orchestration Architecture

The WorkflowOrchestratorService (packages/modules/workflow-engine-redis/src/services/workflow-orchestrator.ts) manages the execution lifecycle and event distribution for all workflows. When you invoke workflow.run(), the orchestrator creates a DistributedTransaction and builds event handlers through the internal buildWorkflowEvents method.

All lifecycle events funnel through the private notify method, which performs two critical operations: it publishes JSON payloads to Redis on the orchestrator:<workflowId> channel (for asynchronous flows) and schedules processSubscriberNotifications to invoke local subscriber callbacks. The service maintains a static subscribers Map that persists listeners across multiple workflow runs unless explicitly cleared by the onFinish event, which automatically removes transaction-specific handlers to prevent memory leaks.

Four Methods to Observe Workflow Execution

1. Programmatic Subscription Using subscribe()

The most direct approach calls WorkflowOrchestratorService.subscribe() with a workflowId and callback function. This registers a handler that receives NotifyOptions containing eventType, step, result, and errors whenever the workflow state changes.

2. Admin UI Monitoring

The Medusa Admin dashboard provides visual observability through the WorkflowExecutionListTable component (packages/admin/dashboard/src/routes/workflow-executions/workflow-execution-list/workflow-execution-list.tsx). The UI polls the /admin/workflows-executions REST endpoint, which internally calls listWorkflowExecutions() on the orchestrator service to retrieve historical and active transaction states.

3. Redis Pub/Sub Channel Listeners

External services can monitor workflows by subscribing to the Redis channel orchestrator:<workflowId>. The orchestrator's notify method publishes execution events to this topic using the injected redisPublisher, allowing language-agnostic consumers to receive real-time updates without direct code integration.

4. Test Utilities with waitWorkflowExecutions()

Integration tests use the waitWorkflowExecutions(container) helper from @medusajs/medusa-test-utils (packages/medusa-test-utils/src/medusa-test-runner-utils/wait-workflow-executions.ts). This utility repeatedly queries listWorkflowExecutions() until no transactions remain in a running state, ensuring test assertions execute only after background workflow processing completes.

Practical Implementation Examples

Subscribing to Workflow Events in Application Code

Attach a subscriber before triggering the workflow to capture every lifecycle event:

import { Modules } from "@medusajs/framework/utils"
import { WorkflowOrchestratorService } from "@medusajs/workflow-engine-redis"
import { MedusaContainer } from "@medusajs/framework/types"

async function registerWorkflowObserver(container: MedusaContainer) {
  const orchestrator = container.resolve(
    Modules.WORKFLOW_ENGINE
  ) as WorkflowOrchestratorService

  orchestrator.subscribe({
    workflowId: "order.create",
    subscriber: async ({ eventType, step, result, errors }) => {
      console.log(`[${eventType}] Step: ${step?.id}`, { result, errors })
    },
  })
}

Source: WorkflowOrchestratorService.subscribe in packages/modules/workflow-engine-redis/src/services/workflow-orchestrator.ts

Synchronizing Tests with Background Execution

Prevent flaky tests by ensuring all workflow activity finishes before assertions:

import { waitWorkflowExecutions } from "@medusajs/medusa-test-utils"

// After triggering workflows in your test...
await waitWorkflowExecutions(container)
// All executions have reached a terminal state

Source: packages/medusa-test-utils/src/medusa-test-runner-utils/wait-workflow-executions.ts

Monitoring via External Redis Consumers

Connect any Redis client to observe workflow events from outside the Medusa application:

import Redis from "ioredis"

const redis = new Redis()
const channel = "orchestrator:order.create"

redis.subscribe(channel, () => {
  console.log(`Subscribed to ${channel}`)
})

redis.on("message", (channel, message) => {
  const { instanceId, data } = JSON.parse(message)
  const { eventType, step, result } = data
  console.log(`Event from ${instanceId}:`, { eventType, step, result })
})

The orchestrator publishes this payload in the notify method via redisPublisher.publish on lines 77-79 of the orchestrator service source.

Summary

  • WorkflowOrchestratorService emits lifecycle events (onBegin, onStepBegin, onStepSuccess, onStepFailure, onFinish) for every DistributedTransaction.
  • Use subscribe() with a specific workflowId to receive in-process callbacks containing execution metadata.
  • Monitor workflows externally by subscribing to the orchestrator:<workflowId> Redis channel.
  • Integration tests should call waitWorkflowExecutions() to block until asynchronous workflow processing completes.
  • The static subscribers map persists listeners across runs, but onFinish automatically cleans up transaction-specific handlers to prevent memory leaks.

Frequently Asked Questions

What lifecycle events does the Medusa workflow orchestrator emit?

The orchestrator emits onBegin when the transaction starts, onStepBegin before each step executes, onStepSuccess or onStepFailure upon step completion, and onFinish when the workflow reaches a terminal state. These events contain the step identifier, execution results, and error objects.

How can an external service listen to Medusa workflow events without modifying the core application?

External services can subscribe to the Redis Pub/Sub channel orchestrator:<workflowId> where <workflowId> matches the workflow registration key. The orchestrator publishes JSON payloads to this channel for all asynchronous workflow executions, allowing polyglot consumers to receive real-time updates.

Why do my workflow subscribers stop receiving events after a workflow completes?

The WorkflowOrchestratorService automatically clears transaction-specific subscribers when it emits the onFinish event. This design prevents memory leaks in long-running server processes. To observe subsequent runs, ensure your subscription logic handles re-registration or subscribes at the application bootstrap level rather than per-request.

How do I verify that all background workflows have finished during integration testing?

Import waitWorkflowExecutions from @medusajs/medusa-test-utils and await it after triggering workflows in your test case. This helper polls listWorkflowExecutions() until no transactions remain in a running state, guaranteeing that all side effects have persisted before your test assertions execute.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →