refactor: made the sms to use queue

This commit is contained in:
2026-07-31 18:46:21 +03:30
parent ac4e34436a
commit a4c50496c5
18 changed files with 306 additions and 73 deletions
+2
View File
@@ -0,0 +1,2 @@
export const SMS_CONFIG = "SMS_CONFIG";
export const SMS_QUEUE = 'sms';
@@ -0,0 +1,24 @@
export interface SmsParameter {
name: SmsTemplateParameter;
value: string;
}
export interface SmsRequest {
Mobile: string;
TemplateId: string;
Parameters: SmsParameter[];
}
export interface SmsResponse {
status: number;
message: string;
}
export interface SmsSendResponse extends SmsResponse {
data: {
MessageId: number;
Cost: number;
};
}
export type SmsTemplateParameter = string;
@@ -0,0 +1,23 @@
import { Module } from '@nestjs/common';
import { BullModule } from '@nestjs/bullmq';
import { SmsService } from './providers/sms.service';
import { SmsProducer } from './producers/sms.producer';
import { SmsProcessor } from './processors/sms.processor';
import { SMS_CONFIG, SMS_QUEUE } from './constants';
import { smsConfigsProvider } from 'src/config/sms.config';
import { HttpModule } from '@nestjs/axios';
@Module({
imports: [
HttpModule,
BullModule.registerQueue({
name: SMS_QUEUE,
}),
],
providers: [SmsService, smsConfigsProvider, SmsProducer, SmsProcessor],
exports: [SmsProducer, SMS_CONFIG],
})
export class NotificationModule {}
export { SMS_QUEUE };
@@ -0,0 +1,22 @@
import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Job } from 'bullmq';
import { Logger } from '@nestjs/common';
import { SMS_QUEUE } from '../constants';
import { SmsService } from '../providers/sms.service';
import { SmsRequest } from '../interfaces/ISms';
@Processor(SMS_QUEUE)
export class SmsProcessor extends WorkerHost {
private readonly logger = new Logger(SmsProcessor.name);
constructor(private readonly smsService: SmsService) {
super();
}
async process(job: Job<SmsRequest>): Promise<void> {
this.logger.log(
`Processing SMS job ${job.id} (attempt ${job.attemptsMade + 1})`,
);
await this.smsService.sendSms(job.data);
}
}
@@ -0,0 +1,19 @@
import { Injectable } from '@nestjs/common';
import { InjectQueue } from '@nestjs/bullmq';
import { Queue } from 'bullmq';
import { SMS_QUEUE } from '../constants';
import { SmsRequest } from '../interfaces/ISms';
@Injectable()
export class SmsProducer {
constructor(@InjectQueue(SMS_QUEUE) private readonly smsQueue: Queue) {}
async sendSms(body: SmsRequest) {
return this.smsQueue.add('send-sms', body, {
attempts: 3,
backoff: { type: 'exponential', delay: 2000 },
removeOnComplete: true,
removeOnFail: false,
});
}
}
@@ -0,0 +1,61 @@
import {
Inject,
Injectable,
InternalServerErrorException,
Logger,
} from '@nestjs/common';
import { SMS_CONFIG } from '../constants';
import type { ISmsConfigs } from 'src/config/sms.config';
import { catchError, firstValueFrom } from 'rxjs';
import { HttpService } from '@nestjs/axios';
import { AxiosError } from 'axios';
import { SmsRequest, SmsSendResponse } from '../interfaces/ISms';
@Injectable()
export class SmsService {
private readonly logger = new Logger(SmsService.name);
constructor(
@Inject(SMS_CONFIG) private smsConfigs: ISmsConfigs,
private readonly httpService: HttpService,
) {}
async sendSms(body: SmsRequest): Promise<SmsSendResponse> {
try {
const { data } = await firstValueFrom(
this.httpService
.post<SmsSendResponse>(
`${this.smsConfigs.API_URL}/send/verify`,
body,
{
headers: {
'X-API-KEY': this.smsConfigs.API_KEY,
},
timeout: 5000,
},
)
.pipe(
catchError((error: AxiosError) => {
this.logger.error(
'Error while calling SMS provider.',
error.stack,
);
throw new InternalServerErrorException(
'Failed to communicate with SMS provider.',
);
}),
),
);
return data;
} catch (error) {
this.logger.error(
'Failed to send SMS.',
error instanceof Error ? error.stack : undefined,
);
throw new InternalServerErrorException('Failed to send SMS.');
}
}
}