npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dudousxd/nestjs-telescope-bullmq

v1.11.0

Published

BullMQ job watcher for @dudousxd/nestjs-telescope.

Downloads

1,081

Readme

@dudousxd/nestjs-telescope-bullmq

BullMQ job watcher for @dudousxd/nestjs-telescope. Captures every job (id, name, queue, outcome, duration, attempts) and correlates the queries and exceptions a job emits to that job's batch.

Install

pnpm add @dudousxd/nestjs-telescope-bullmq

Peer deps: @dudousxd/nestjs-telescope, @nestjs/bullmq, bullmq, @nestjs/common, @nestjs/core, reflect-metadata.

Usage

Add the watcher to TelescopeModule. No host wiring is required — the watcher discovers your @Processor (WorkerHost) classes and instruments them automatically.

import { TelescopeModule } from '@dudousxd/nestjs-telescope';
import { BullMqJobWatcher } from '@dudousxd/nestjs-telescope-bullmq';

@Module({
  imports: [
    TelescopeModule.forRoot({
      watchers: [new BullMqJobWatcher({ slowMs: 1000 })],
    }),
    // ...your BullModule.registerQueue(...) and @Processor classes
  ],
})
export class AppModule {}

Each processed job becomes a job entry with origin: 'queue'. Queries and exceptions emitted while the job runs share the job's batchId, so opening a job in the dashboard shows everything it caused.

With these entries captured, the core endpoint GET /telescope/api/queues?window=1h reports per-queue throughput, runtime and wait-time percentiles, and failure rate (wait time = processedOn − enqueue).

Live queue reads (BullMqQueueManager)

The watcher above records what jobs did. BullMqQueueManager is the complementary read side: it browses your queues' current state directly via the BullMQ Queue API (counts, paused flag, and the jobs sitting in each list), so the dashboard can show live queue depth and inspect individual jobs.

It is a QueueManager, passed via the queueManagers option (not watchers). At bootstrap it discovers every @nestjs/bullmq Queue instance in the Nest container through DiscoveryService (duck-typed — no extra wiring):

import { TelescopeModule } from '@dudousxd/nestjs-telescope';
import { BullMqQueueManager } from '@dudousxd/nestjs-telescope-bullmq';

@Module({
  imports: [
    TelescopeModule.forRoot({
      queueManagers: [new BullMqQueueManager()],
    }),
    BullModule.forRoot({ connection }),
    BullModule.registerQueue({ name: 'mail' }),
  ],
})
export class AppModule {}

Pass an explicit allow-list to expose only some queues: new BullMqQueueManager(['mail', 'reports']).

This surfaces these read endpoints on the core controller, under the existing Telescope authorizer (same gate as the rest of the dashboard):

| Method & path | Returns | |---------------|---------| | GET /telescope/api/queues/live | { queues: QueueSummary[] } across all drivers — name, per-state counts, isPaused. | | GET /telescope/api/queues/live/bullmq/:queue/counts | QueueCounts for one queue. | | GET /telescope/api/queues/live/bullmq/:queue/jobs?state=&cursor=&limit= | A JobPage of jobs in state (waiting/active/delayed/failed/completed/paused); nextCursor paginates. | | GET /telescope/api/queues/live/bullmq/:queue/jobs/:id | A QueueJobDetail (adds redacted data, opts, stacktrace, returnValue). |

Job payloads (data) are passed through core redaction before they leave the server, so secret-keyed fields (e.g. password, token) are masked.

Queue actions (mutations)

BullMqQueueManager also implements the action side of the QueueManager SPI — retry, remove, promote, and retryAll — backed by the real BullMQ Job.retry() / Job.remove() / Job.promote() and Queue.retryJobs() APIs. These surface as POST endpoints on the core controller:

| Method & path | Effect | |---------------|--------| | POST /telescope/api/queues/live/bullmq/:queue/jobs/:id/retry | Re-queue a failed (or completed) job. | | POST /telescope/api/queues/live/bullmq/:queue/jobs/:id/remove | Delete a job. | | POST /telescope/api/queues/live/bullmq/:queue/jobs/:id/promote | Promote a delayed job to run now. | | POST /telescope/api/queues/live/bullmq/:queue/actions/retry-all?state=failed | Bulk re-queue every job in state; responds { ok: true, count } (the pre-action count). |

redrive is SQS-only and is not implemented by BullMqQueueManager; calling .../actions/redrive against the bullmq driver returns 405 Method Not Allowed.

Enabling mutations — authorizeAction (default-deny)

Mutations are denied by default. They run behind a second guard (TelescopeActionGuard) on top of the read authorizer, and that guard fails closed: without an authorizeAction callback, every mutation endpoint returns 403 — even for callers the read authorizer already trusts. Opt in by supplying authorizeAction on TelescopeModule.forRoot:

TelescopeModule.forRoot({
  // Reads (browse queues/jobs) — the existing gate:
  authorizer: (ctx) => isAdmin(ctx.request),
  // Mutations (retry/remove/promote/retry-all) — separate, default-deny:
  authorizeAction: (ctx, action) => {
    // action: { driver, queue, action, jobId?, state? }
    return canMutateQueues(ctx.request);
  },
  queueManagers: [new BullMqQueueManager()],
});

authorizeAction receives the same AuthorizerContext plus a typed QueueActionRequest describing the requested mutation. Returning a falsy value — or throwing — denies the request (403). Keep it strictly narrower than your read gate: browsing a queue should not imply the right to drain it.

Options

| Option | Default | Description | |--------|---------|-------------| | slowMs | 1000 | Jobs taking at least this long get a slow tag. | | includeJobData | true | Capture job.data as the entry payload (core redaction still applies). | | clock | wall clock | Injectable time source (for tests). |

Not included

This watcher captures per-job entries; the aggregate queue metrics above are computed in core from those entries (GET /telescope/api/queues). Broader health rollups — N+1 insights, slowest request/query/job, top exceptions, and a visual dashboard — are the concern of @dudousxd/nestjs-telescope-pulse and @dudousxd/nestjs-telescope-ui, not this watcher.