I am trying to integrate bullmq
in NestJs project. But facing the following error:
Error: Nest can't resolve dependencies of the CustomerSubscriptionPaymentsService (CustomerSubscriptionPaymentsRepo, ?). Please make sure that the argument "BullQueue_invoice" at index [1] is available in the CustomerSubscriptionPaymentsModule context.
Potential solutions:
- Is CustomerSubscriptionPaymentsModule a valid NestJS module?
- If "BullQueue_invoice" is a provider, is it part of the current CustomerSubscriptionPaymentsModule?
- If "BullQueue_invoice" is exported from a separate @Module, is that module imported within CustomerSubscriptionPaymentsModule?
@Module({
imports: [ /* the Module containing "BullQueue_invoice" */ ]
})
Here is the project directory:
modules
app
app.module.ts
app.controller.ts
customerSubscriptionPayments
customerSubscriptionPayments.module.ts
customerSubscriptionPayments.service.ts
customerSubscriptionPayments.controller.ts
invoice
invouce.module.ts
invoice.controller.ts
invoice.service.ts
invoice.processor.ts
app.module.ts
import { Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bullmq';
import { AppController } from './app.controller';
import { CustomerSubscriptionPaymentsModule } from '../customerSubscriptionPayments/customerSubscriptionPayments.module';
import { CustomerSubscriptionPaymentsService } from '../customerSubscriptionPayments/customerSubscriptionPayments.service';
@Module({
imports: [
BullModule.forRoot({
connection: {
host: 'localhost',
port: 6379,
},
}),
CustomerSubscriptionPaymentsModule,
],
providers: [CustomerSubscriptionPaymentsService],
controllers: [AppController],
})
export class AppModule {}
invoice.module.ts
import { Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bullmq';
import { InvoiceController } from './invoice.controller';
import { InvoiceService } from './invoice.service';
import { InvoiceRepo } from './invoice.repo';
import { RedisQueues } from 'src/constants';
import { InvoiceProcessor } from './invoice.processor';
@Module({
imports: [
BullModule.registerQueue({
name: 'invoice',
}),
],
controllers: [InvoiceController],
providers: [InvoiceService, InvoiceRepo],
exports: [InvoiceService, InvoiceRepo],
})
export class InvoiceModule {}
invoice.processor.ts
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Job } from 'bullmq';
import { InvoiceQueueTasks } from './constants';
@Processor('invoice')
export class InvoiceProcessor extends WorkerHost {
async generateInvoice(job: Job) {
const { data } = job;
if (data.customerSubscriptionId) {
console.error('customerSubscriptionId not found');
return {};
}
//TODO: Implement invoice generation logic
}
async process(job: Job) {
const { data, name } = job;
if (name === InvoiceQueueTasks.GENERATE) {
return this.generateInvoice(job);
}
return {};
}
}
customerSubscriptionPayments.module.ts
import { Module } from '@nestjs/common';
import { CustomerSubscriptionPaymentsController } from './customerSubscriptionPayments.controller';
import { CustomerSubscriptionPaymentsRepo } from './customerSubscriptionPayments.repo';
import { CustomerSubscriptionPaymentsService } from './customerSubscriptionPayments.service';
@Module({
controllers: [CustomerSubscriptionPaymentsController],
providers: [
CustomerSubscriptionPaymentsService,
CustomerSubscriptionPaymentsRepo,
],
exports: [
CustomerSubscriptionPaymentsService,
CustomerSubscriptionPaymentsRepo,
],
})
export class CustomerSubscriptionPaymentsModule {}
customerSubscriptionPayments.service.ts
import { InjectQueue } from '@nestjs/bullmq';
import { Queue } from 'bullmq';
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
@Injectable()
export class CustomerSubscriptionPaymentsService {
constructor(@InjectQueue('invoice') private invoiceQueue: Queue) {}
async generateInvoice() {
const job = await this.invoiceQueue.add('generate', {
customerSubscriptionId: 1,
});
if (!job) {
throw new HttpException(
'Failed to generate invoice',
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
return {
success: true,
};
}
}
The problem is that you are not importing your Bull Queue into your customerSubscriptionPayments Module, that's why when you try to inject it in the customerSubscriptionPayments Service it won't be able to resolve the dependency.
@Module({
imports: [
BullModule.registerQueue({
name: 'invoice',
}),
]
controllers: [CustomerSubscriptionPaymentsController],
providers: [
CustomerSubscriptionPaymentsService,
CustomerSubscriptionPaymentsRepo,
],
exports: [
CustomerSubscriptionPaymentsService,
CustomerSubscriptionPaymentsRepo,
],
})
Another way of doing things
Since in NestJS docs there's no documentation that shows how to export a registered Bull Queue you could create a Module
that exports a Service
that handles the queue independently, after that you can import that module into other services so you can add, delete or do any queue related action within any service you need to. You could do this in your Invoice Module
since that's the place you were registering the queue in the first place.
Example:
Invoice Module
@Module({
imports: [
BullModule.registerQueue({
name: 'invoice',
}),
],
controllers: [InvoiceController],
providers: [InvoiceService, InvoiceRepo, InvoiceQueueHandler],
exports: [InvoiceService, InvoiceRepo, InvoiceQueueHandler],
})
export class InvoiceModule {}
Invoice Queue Handler
export class InvoiceQueueHandler(){
constructor(InjectQueue('invoice') private invoiceQueue: Queue){}
addJob(){
// perform some action
}
// rest of your functions to handle the queue
}
customerSubscriptionPayments Module
@Module({
import: [InvoiceModule]
controllers: [CustomerSubscriptionPaymentsController],
providers: [
CustomerSubscriptionPaymentsService,
CustomerSubscriptionPaymentsRepo,
],
exports: [
CustomerSubscriptionPaymentsService,
CustomerSubscriptionPaymentsRepo,
],
})
export class CustomerSubscriptionPaymentsModule {}
customerSubscriptionPayments Module
@Injectable()
export class CustomerSubscriptionPaymentsService {
constructor(private invoiceQueueHandler: InvoiceQueueHandler) {}
someFunction(){
this.invoiceQueueHandler.addJob()
}
}