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

# BullMQ

> Instrument BullMQ job queues for observability

This guide covers how to instrument BullMQ queues and workers. You will learn how to:

* Install and configure the instrumentation
* Track job dispatch and processing
* Understand producer and consumer spans

For the full list of required span attributes and what powers the Jobs dashboard, see the [Jobs feature page](/features/jobs).

## Installation

```bash theme={"theme":"vesper"}
npm install @monocle.sh/instrumentation-bullmq
```

**Peer dependency:** `bullmq >= 5.0.0`

## Usage

Create an instance of `BullMQInstrumentation` and call `enable()`. This must happen before you import or create any BullMQ `Queue`, `Worker`, or `FlowProducer` instances.

```typescript title="instrumentation.ts" theme={"theme":"vesper"}
import { BullMQInstrumentation } from "@monocle.sh/instrumentation-bullmq";

const instrumentation = new BullMQInstrumentation();
instrumentation.enable();
```

Once enabled, all `Queue.add`, `Queue.addBulk`, `FlowProducer.add`, `FlowProducer.addBulk`, and `Worker` processing calls are automatically instrumented.

```typescript title="example.ts" theme={"theme":"vesper"}
import { Queue, Worker } from "bullmq";

const queue = new Queue("emails", { connection });

// This creates a PRODUCER span
await queue.add("welcome-email", { userId: "123" });

// This creates a CONSUMER span for each processed job
const worker = new Worker("emails", async (job) => {
  await sendEmail(job.data.userId);
}, { connection });
```

## Configuration

```typescript theme={"theme":"vesper"}
const instrumentation = new BullMQInstrumentation({
  // Create individual spans for each job in addBulk (default: true)
  emitCreateSpansForBulk: true,

  // Create individual spans for each job in FlowProducer.add (default: true)
  emitCreateSpansForFlow: true,

  // Only create producer spans when a parent span exists (default: false)
  requireParentSpanForPublish: false,

  // Use producer span as consumer parent instead of linking (default: false)
  useProducerSpanAsConsumerParent: false,
});
```

### Span linking vs parenting

By default, consumer spans are **linked** to the producer span. This means they appear as separate traces connected by a link. Set `useProducerSpanAsConsumerParent: true` to make the consumer span a **child** of the producer, keeping them in the same trace.

## Spans

### Producer spans

**`Queue.add`** creates a **PRODUCER** span named `Queue.add {queueName}`.

**`Queue.addBulk`** creates an **INTERNAL** parent span named `Queue.addBulk {queueName}`, with individual **PRODUCER** child spans for each job (named `Job.addJob {queueName}`).

**`FlowProducer.add`** creates an **INTERNAL** parent span named `FlowProducer.add {queueName}`, with child spans for each job in the flow tree.

**`FlowProducer.addBulk`** creates an **INTERNAL** parent span named `FlowProducer.addBulk`, with child spans per flow.

### Consumer spans

**`Worker` processing** creates a **CONSUMER** span named `Worker.run {queueName}` for each job processed. The span captures job metadata, queue time, and any errors thrown during processing.

### Lifecycle events

Lock extensions, job removals, and retries are recorded as **events** on the active consumer span (not separate spans).

## BullMQ-specific attributes

In addition to the [standard job attributes](/features/jobs#span-attributes), the BullMQ instrumentation emits these extra attributes:

| Attribute                                      | Description                           |
| ---------------------------------------------- | ------------------------------------- |
| `messaging.bullmq.job.name`                    | Job name                              |
| `messaging.bullmq.job.timestamp`               | Job creation timestamp                |
| `messaging.bullmq.job.delay`                   | Job delay in ms                       |
| `messaging.bullmq.job.attempts`                | Total attempts made                   |
| `messaging.bullmq.job.failedReason`            | Failure reason (set after processing) |
| `messaging.bullmq.job.finishedOn`              | Completion timestamp                  |
| `messaging.bullmq.job.processedOn`             | Processing start timestamp            |
| `messaging.bullmq.job.repeatJobKey`            | Repeat job key (for recurring jobs)   |
| `messaging.bullmq.job.bulk.names`              | Array of job names in bulk operations |
| `messaging.bullmq.worker.concurrency`          | Worker concurrency setting            |
| `messaging.bullmq.worker.lockDuration`         | Lock duration in ms                   |
| `messaging.bullmq.worker.lockRenewTime`        | Lock renew interval in ms             |
| `messaging.bullmq.worker.rateLimiter.max`      | Rate limiter max                      |
| `messaging.bullmq.worker.rateLimiter.duration` | Rate limiter duration                 |
