Skip to content
Back to skills

Add Queue Job

ASecurity

Add a new BullMQ job queue to the project — processor, producer injection, module registration, Bull Board integration, and unit tests.

  • 30 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 8, 2026
developmenttypescripttestingapi

Works with

  • api

Security analysis

A100/100

Scanned June 8, 2026

npx -y skills add uxname/liteend --skill add-queue-job --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Add Queue Job?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Add Queue Job
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/uxname-add-queue-job/badge)](https://www.skillsdirectory.com/skills/uxname-add-queue-job)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: add-queue-job
description: Add a new BullMQ job queue to the project — processor, producer injection, module registration, Bull Board integration, and unit tests.
---

The user wants to add a new BullMQ job queue to the project. They will provide the queue name and describe what the job should do.

## Project BullMQ setup

- Package: `@nestjs/bullmq` (NestJS wrapper) + `bullmq`
- Redis connection is configured globally in `BullModule.forRootAsync` in `app.module.ts`
- Bull Board is integrated via `@bull-board/nestjs` — each queue must register itself there
- Reference implementation: `src/infrastructure/test-queue/`

## Files to create

```
src/infrastructure/<queue-name>/
  <queue-name>.module.ts
  <queue-name>.processor.ts
  <queue-name>.service.ts    (producer — injectable into other modules)
  <queue-name>.spec.ts
```

If the queue is tightly coupled to a business module, place it in `src/modules/<module>/` instead.

## File templates

### `<queue-name>.processor.ts`
```typescript
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Logger } from '@nestjs/common';
import { Job } from 'bullmq';

export interface <QueueName>JobData {
  // define typed job payload here
}

@Processor('<queue-name>')
export class <QueueName>Processor extends WorkerHost {
  private readonly logger = new Logger(<QueueName>Processor.name);

  async process(job: Job<<QueueName>JobData>): Promise<unknown> {
    this.logger.log(`Processing job ${job.id} (${job.name})`);

    // job logic here

    this.logger.log(`Finished job ${job.id}`);
    return { result: 'Success' };
  }
}
```

### `<queue-name>.service.ts` (producer)
```typescript
import { InjectQueue } from '@nestjs/bullmq';
import { Injectable } from '@nestjs/common';
import { Queue } from 'bullmq';
import { <QueueName>JobData } from './<queue-name>.processor';

@Injectable()
export class <QueueName>Service {
  constructor(
    @InjectQueue('<queue-name>') private readonly queue: Queue,
  ) {}

  async add<JobName>(data: <QueueName>JobData): Promise<void> {
    await this.queue.add('<job-name>', data);
  }
}
```

### `<queue-name>.module.ts`
```typescript
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
import { BullBoardModule } from '@bull-board/nestjs';
import { BullModule } from '@nestjs/bullmq';
import { Module } from '@nestjs/common';
import { <QueueName>Processor } from './<queue-name>.processor';
import { <QueueName>Service } from './<queue-name>.service';

@Module({
  imports: [
    BullModule.registerQueue({
      name: '<queue-name>',
    }),
    BullBoardModule.forFeature({
      name: '<queue-name>',
      adapter: BullMQAdapter,
    }),
  ],
  providers: [<QueueName>Processor, <QueueName>Service],
  exports: [<QueueName>Service],
})
export class <QueueName>Module {}
```

### `<queue-name>.spec.ts`
```typescript
import { Logger } from '@nestjs/common';
import { Job } from 'bullmq';
import { Test } from '@nestjs/testing';
import { getQueueToken } from '@nestjs/bullmq';
// Globals (describe, it, expect, vi, beforeEach, afterEach) are available without import (vitest globals: true)
// Import path to mocks is relative — adjust depth based on file location:
//   src/infrastructure/<queue-name>/  → '../../../test/utils/mocks'
//   src/modules/<module>/            → '../../../test/utils/mocks'
import { createJobMock } from '../../../test/utils/mocks';
import { <QueueName>Processor } from './<queue-name>.processor';
import { <QueueName>Service } from './<queue-name>.service';

describe('<QueueName>Processor', () => {
  let processor: <QueueName>Processor;

  const buildJob = (data?: Partial<Job>): Job => {
    const job = createJobMock();
    job.id = data?.id ?? '1';
    job.name = data?.name ?? '<job-name>';
    job.data = data?.data ?? { /* default test data */ };
    return job;
  };

  beforeEach(() => {
    processor = new <QueueName>Processor();
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  it('should process job and return success', async () => {
    const result = await processor.process(buildJob());
    expect(result).toEqual({ result: 'Success' });
  });

  it('should log start and finish', async () => {
    const logSpy = vi.spyOn(Logger.prototype, 'log');
    const job = buildJob();
    await processor.process(job);
    expect(logSpy).toHaveBeenCalledWith(expect.stringContaining(String(job.id)));
  });
});

describe('<QueueName>Service', () => {
  let service: <QueueName>Service;

  const mockQueue = {
    add: vi.fn().mockResolvedValue(undefined),
  };

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        <QueueName>Service,
        {
          provide: getQueueToken('<queue-name>'),
          useValue: mockQueue,
        },
      ],
    }).compile();

    service = module.get(<QueueName>Service);
  });

  afterEach(() => {
    vi.clearAllMocks();
  });

  it('should add job to queue', async () => {
    // Replace add<JobName> with the actual method name, e.g. addEmail, addReport
    await service.add<JobName>({ /* test data matching <QueueName>JobData */ } as <QueueName>JobData);
    expect(mockQueue.add).toHaveBeenCalledWith('<job-name>', expect.any(Object));
  });
});
```

## Registration in AppModule

Add the new module to `src/app.module.ts` imports array:

```typescript
import { <QueueName>Module } from '@/infrastructure/<queue-name>/<queue-name>.module';

// in @Module imports:
<QueueName>Module,
```

## Steps

1. Clarify the queue name, job name, and job payload structure if not provided
2. Create the four files above
3. Register in `app.module.ts`
4. Run `npm run check` to verify everything compiles

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.