bull-board

repository·master·Indexed 25 days ago

https://github.com/felixmosh/bull-board

A Dashboard UI for monitoring Bull and BullMQ job queues. It provides a visual interface for inspecting jobs and monitoring queue activity, with server adapters for Express, Fastify, H3, Hapi.js, Hono, Koa.js, Bun, and NestJS. The library includes features like visibilityGuard for restricting queue access and supports various authentication methods including Basic Auth, Cookie-based auth, and Passport strategies.

Tokens
47.9K
Snippets
105
Records
248
Agent score
80%

What's inside bull-board

  1. Overview of @bull-board/ui packages

    master
    @bull-board/ui contains the UI packages for bull-board. These packages provide the visual dashboard interface for monitoring and managing Bull queues. Instead of using the core UI package directly, users typically install framework-specific adapters (e.g., @bull-board/fastify, @bull-board/express, @bull-board/hono) to integrate the dashboard into their existing web server.
  2. Introduction to Bull-Board

    master

    Bull-Board is a React-based dashboard for visualizing BullMQ and Bull queues. It mounts directly into your existing HTTP server and provides a visual interface for monitoring what is stored in Redis.

    Key Features:

    • Real-time Monitoring: View job counts, individual jobs, logs, and live updates via a React dashboard.
    • Framework Adapters: Official support for Express, Fastify, Koa, Hapi, NestJS, Hono, H3, Elysia, and Bun.
    • Advanced Controls: Per-queue read-only mode, custom formatters, external job URLs, and a visibility guard for multi-tenant environments.
    • Privacy & Control: Self-hosted with no telemetry; it runs inside your application and communicates directly with your Redis instance.
  3. Overview of Bull-Board features

    master

    Bull-Board is a self-hosted dashboard for managing BullMQ, BullMQ Pro, and Bull queues. It runs within your application and connects directly to your Redis instance without third-party telemetry.

    Key features include:

    • Multi-stack support: Adapters available for Express, Fastify, Koa, Hapi, NestJS, Hono, H3, Elysia, and Bun.
    • Read-only mode: Allows sharing the dashboard without enabling job manipulation (like retry).
    • Multi-tenant support: Use a visibility guard to scope queue visibility per request.
    • Formatters: Customize how job data is displayed without modifying producers.
    • Queue Support: Native support for BullMQ, BullMQ Pro, and Bull.
  4. Choose a server adapter for your framework

    master

    Bull board provides dedicated server adapters for various web frameworks. All adapters share the core @bull-board/api package and serve the same UI. Choose the package that matches your framework:

    FrameworkPackage
    Express@bull-board/express
    Fastify@bull-board/fastify
    NestJS@bull-board/nestjs
    Koa@bull-board/koa
    Hapi@bull-board/hapi
    Hono@bull-board/hono
    H3@bull-board/h3
    Elysia@bull-board/elysia
    Bun@bull-board/bun
  5. Enable long-retention historical job metrics with @bull-board/metrics

    master

    The @bull-board/metrics package allows you to opt-in to long-retention historical job metrics for bull-board. It snapshots native BullMQ per-minute metrics into long-retention Redis buckets and provides a MetricsHistoryProvider to feed bull-board's history charts.

    Note: This feature is in Beta. The API and Redis storage layout may change in minor releases. It is recommended to pin an exact version if you depend on the storage format.

  6. Deployment Architecture: Next.js vs BullMQ Workers

    master

    When using Next.js with Vercel, it is important to distinguish between the dashboard and the workers:

    1. Dashboard/API Routes: These run inside Next.js (serverless functions) and can be deployed to Vercel.
    2. BullMQ Workers: These are long-running processes and cannot run inside serverless functions. They must run as a separate always-on process, such as a container, a VM, or a dedicated worker service.
  7. Use built-in queue adapters

    master

    Queue adapters wrap your Bull or BullMQ queue instances so the board can read and manipulate them. The @bull-board/api package provides three built-in adapters:

    • BullAdapter: For Bull queues.
    • BullMQAdapter: For BullMQ queues.
    • BullMQProAdapter: For BullMQ Pro queues. This extends BullMQAdapter to handle Pro groups; all BullMQAdapter options are compatible.

    Third-party queue systems can also provide their own adapters.

  8. Understand UI changes with Historical Metrics enabled

    master

    When a historyProvider is configured, the UI changes in two ways:

    1. Per-Queue Metrics Charts: If showMetrics: true is set in uiConfig, each queue page gains a range selector (60m, 7d, 30d, 90d). The 60m view uses live native data, while longer ranges use the history provider. If showMetrics is false, the chart is hidden.
    2. Metrics History Page: A new page appears in the sidebar (independent of showMetrics). This provides a cross-queue 'wallboard' view showing total completed/failed throughput across all registered queues, plus a per-queue breakdown table. The table includes bars representing volume and outcome (completed vs failed) for each queue.

    Scope & Limitations:

    • BullMQ Only: This feature does not work with Bull v3 as it lacks native metrics to snapshot.
    • Tracked Data: Only 'completed' and 'failed' throughput are tracked. Other job states or job data are not included in history.
  9. Add authentication to Hapi using strategies

    master

    In Hapi, you can protect the bull-board dashboard by registering a strategy (such as @hapi/basic) and passing the strategy name to the auth option within the serverAdapter.registerPlugin() options.

    await app.register(require('@hapi/basic'));
    app.auth.strategy('simple', 'basic', {
      validate: async (_req, username, password) => ({
        isValid: username === 'bull' && password === 'board',
        credentials: { username },
      }),
    });
    
    const serverAdapter = new HapiAdapter();
    createBullBoard({ queues: [new BullMQAdapter(queue)], serverAdapter });
    serverAdapter.setBasePath('/ui');
    
    await app.register(
      { plugin: serverAdapter.registerPlugin(), options: { auth: 'simple' } },
      { routes: { prefix: '/ui' } }
    );
  10. Route permanently-failed jobs to a dead-letter queue (DLQ)

    master

    To prevent failed jobs from cluttering your main queue, you can route jobs that have exhausted all retries to a dedicated 'dead-letter' queue. You can then register this DLQ on the bull-board so you can inspect and replay failed work easily. It is recommended to mark the DLQ as read-only if it is intended only for inspection.

    const deadLetters = new Queue('emails-dead-letter', { connection });
    
    worker.on('failed', async (job, err) => {
      if (job && job.attemptsMade >= (job.opts.attempts ?? 1)) {
        await deadLetters.add('dead', { original: job.data, reason: err.message });
      }
    });
    
    // Register both on the board so the DLQ is one click away.
    createBullBoard({
      queues: [new BullMQAdapter(emailsQueue), new BullMQAdapter(deadLetters)],
      serverAdapter,
    });
  11. Implement alerting for failed jobs in the worker process

    master

    Since bull-board is a viewer and not a monitor, you must implement alerting within your worker code using BullMQ events. To avoid being alerted on every intermediate retry, check if the job's attemptsMade has reached its maximum allowed attempts. Additionally, always attach an error listener to the worker to prevent unhandled exceptions from crashing the process.

    import { Worker } from 'bullmq';
    
    const worker = new Worker('emails', processor, { connection });
    
    // Listen for failures to trigger alerts
    worker.on('failed', (job, err) => {
      // `failed` fires on every attempt. Only alert once retries are exhausted.
      const exhausted = !job || job.attemptsMade >= (job.opts.attempts ?? 1);
      if (exhausted) {
        notifyOnCall(`Job ${job?.id} on "emails" failed for good: ${err.message}`);
      }
    });
    
    // Always attach an error listener to prevent process crashes
    worker.on('error', (err) => {
      logger.error({ err }, 'bullmq worker error');
    });