chore: add loger for the telegram sender

This commit is contained in:
mahyargdz
2025-03-28 16:10:12 +03:30
parent cb9860853e
commit 0b62341908
13 changed files with 200 additions and 85 deletions
+5
View File
@@ -7,11 +7,13 @@ import { ConfigModule } from "@nestjs/config";
import { ThrottlerModule } from "@nestjs/throttler";
import { TypeOrmModule } from "@nestjs/typeorm";
import { MailerModule } from "@nestjs-modules/mailer";
import { TelegrafModule } from "nestjs-telegraf";
import { bullMqConfig } from "./configs/bullmq.config";
import { cacheConfig } from "./configs/cache.config";
import { mailerConfig } from "./configs/mailer.config";
import { rateLimitConfig } from "./configs/rateLimit.config";
import { telegrafConfig } from "./configs/telegraf.config";
import { databaseConfigs } from "./configs/typeorm.config";
import { HTTPLogger } from "./core/middlewares/logger.middleware";
import { AddressModule } from "./modules/address/address.module";
@@ -24,6 +26,7 @@ import { DanakServicesModule } from "./modules/danak-services/danak-services.mod
import { DashboardModule } from "./modules/dashboards/dashboard.module";
import { InvoicesModule } from "./modules/invoices/invoices.module";
import { LearningModule } from "./modules/learnings/learning.module";
import { LoggerModule } from "./modules/logger/logger.module";
import { NotificationModule } from "./modules/notifications/notifications.module";
import { PaymentsModule } from "./modules/payments/payments.module";
import { SettingModule } from "./modules/settings/settings.module";
@@ -35,6 +38,7 @@ import { WalletsModule } from "./modules/wallets/wallets.module";
@Module({
imports: [
TelegrafModule.forRootAsync(telegrafConfig()),
MailerModule.forRootAsync(mailerConfig()),
BullModule.forRootAsync(bullMqConfig()),
ThrottlerModule.forRootAsync(rateLimitConfig()),
@@ -61,6 +65,7 @@ import { WalletsModule } from "./modules/wallets/wallets.module";
AdsModule,
AddressModule,
DashboardModule,
LoggerModule,
],
controllers: [],
providers: [],
+3 -4
View File
@@ -9,10 +9,9 @@ export function bullMqConfig(): SharedBullAsyncConfiguration {
url: configService.getOrThrow<string>("REDIS_URI"),
},
defaultJobOptions: {
removeOnComplete: 2000, // Consider lower values in high-volume production
removeOnFail: 5000, // Consider lower values to reduce Redis memory usage
attempts: 3, // Reasonable default, adjust based on job criticality
backoff: { type: "exponential", delay: 2000 }, // Consider adding for better retry behavior
removeOnComplete: false,
removeOnFail: false,
attempts: 5, // Reasonable default, adjust based on job criticality
},
}),
};
+12
View File
@@ -0,0 +1,12 @@
import { ConfigService } from "@nestjs/config";
import { TelegrafModuleAsyncOptions } from "nestjs-telegraf";
export function telegrafConfig(): TelegrafModuleAsyncOptions {
return {
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
token: configService.getOrThrow<string>("TELEGRAM_BOT_TOKEN"),
botName: configService.getOrThrow<string>("TELEGRAM_BOT_NAME"),
}),
};
}
+1 -1
View File
@@ -5,7 +5,7 @@ export const ANNOUNCEMENT = Object.freeze({
//
ANNOUNCEMENT_SEND_JOB_PRIORITY: 1,
ANNOUNCEMENT_SEND_JOB_ATTEMPTS: 3,
ANNOUNCEMENT_SEND_JOB_BACKOFF: 1000,
ANNOUNCEMENT_SEND_JOB_BACKOFF: 5 * 1000,
ANNOUNCEMENT_SEND_JOB_TIMEOUT: 10000,
//
ANNOUNCEMENT_PUBLISH_JOB_PRIORITY: 1,
@@ -57,7 +57,7 @@ export class AnnouncementService {
{
delay: dayjs(announcement.publishAt).diff(dayjs(), "millisecond"),
attempts: ANNOUNCEMENT.ANNOUNCEMENT_SEND_JOB_ATTEMPTS,
backoff: ANNOUNCEMENT.ANNOUNCEMENT_SEND_JOB_BACKOFF,
backoff: { type: "exponential", delay: ANNOUNCEMENT.ANNOUNCEMENT_SEND_JOB_BACKOFF },
},
);
+9 -9
View File
@@ -3,17 +3,17 @@ export const INVOICE = Object.freeze({
INVOICE_REMINDER_JOB_NAME: "reminderInvoice",
INVOICE_RECURRING_JOB_NAME: "recurringInvoice",
//
INVOICE_REMINDER_JOB_PRIORITY: 1, // High priority
INVOICE_REMINDER_JOB_ATTEMPTS: 3, // Retry 3 times
INVOICE_REMINDER_JOB_BACKOFF: 1000, // Retry after 1 second
INVOICE_REMINDER_JOB_TIMEOUT: 10000, // Timeout after 10 seconds
INVOICE_REMINDER_REPEAT_DELAY: 86400000, // 1 day delay in milliseconds
INVOICE_REMINDER_JOB_PRIORITY: 1, // high priority
INVOICE_REMINDER_JOB_ATTEMPTS: 3, // 3 times
INVOICE_REMINDER_JOB_BACKOFF: 5 * 1000, // ms
INVOICE_REMINDER_JOB_TIMEOUT: 10000, // timeout after 10 seconds
INVOICE_REMINDER_REPEAT_DELAY: 1 * 24 * 60 * 60 * 1000, // 1 day delay in milliseconds
//
INVOICE_RECURRING_JOB_PRIORITY: 1, // High priority
INVOICE_RECURRING_JOB_ATTEMPTS: 3, // Retry 3 times
INVOICE_RECURRING_JOB_BACKOFF: 1000, // Retry after 1 second
INVOICE_RECURRING_JOB_TIMEOUT: 10000, // Timeout after 10 seconds
INVOICE_RECURRING_JOB_PRIORITY: 1, // high priority
INVOICE_RECURRING_JOB_ATTEMPTS: 3, // retry 3 times
INVOICE_RECURRING_JOB_BACKOFF: 5 * 1000, // retry after 1 second
INVOICE_RECURRING_JOB_TIMEOUT: 10000, // timeout after 10 seconds
//
FINE_PERCENTAGE: 0.01, // 1% of the total price
MAX_DAYS_AFTER_OVERDUE: 10,
+2
View File
@@ -18,9 +18,11 @@ import { UtilsModule } from "../utils/utils.module";
import { WalletsModule } from "../wallets/wallets.module";
import { InvoiceProcessor } from "./queue/invoice.processor";
import { InvoiceItemsRepository } from "./repositories/invoice-items.repository";
import { LoggerModule } from "../logger/logger.module";
@Module({
imports: [
LoggerModule,
BullModule.registerQueue({ name: INVOICE.INVOICE_QUEUE_NAME }),
TypeOrmModule.forFeature([Invoice, InvoiceItem, Discount, UsageDiscount]),
UsersModule,
@@ -1,5 +1,4 @@
import { InjectQueue, Processor } from "@nestjs/bullmq";
import { Logger } from "@nestjs/common";
import { Job, Queue } from "bullmq";
import dayjs from "dayjs";
// eslint-disable-next-line import/no-named-as-default
@@ -7,6 +6,7 @@ import Decimal from "decimal.js";
import { DataSource, QueryRunner } from "typeorm";
import { WorkerProcessor } from "../../../common/queues/worker.processor";
import { LoggerService } from "../../logger/logger.service";
import { NotificationsService } from "../../notifications/providers/notifications.service";
import { SubscriptionStatus } from "../../subscriptions/enums/subscription-status.enum";
import { User } from "../../users/entities/user.entity";
@@ -16,21 +16,22 @@ import { Invoice } from "../entities/invoice.entity";
import { InvoiceStatus } from "../enums/invoice-status.enum";
import { InvoicesService } from "../providers/invoices.service";
@Processor(INVOICE.INVOICE_QUEUE_NAME)
@Processor(INVOICE.INVOICE_QUEUE_NAME, { concurrency: 5 })
export class InvoiceProcessor extends WorkerProcessor {
protected readonly logger = new Logger(InvoiceProcessor.name);
// protected readonly logger = new Logger(InvoiceProcessor.name);
constructor(
@InjectQueue(INVOICE.INVOICE_QUEUE_NAME) private readonly invoiceQueue: Queue,
private readonly invoicesService: InvoicesService,
private readonly dataSource: DataSource,
private readonly notificationService: NotificationsService,
protected readonly logger: LoggerService,
) {
super();
}
async process(job: Job, token?: string) {
this.logger.log(job, token);
this.logger.log(job);
switch (job.name) {
case INVOICE.INVOICE_REMINDER_JOB_NAME:
return this.sendBillInvoiceReminder(job, token);
@@ -234,7 +235,7 @@ export class InvoiceProcessor extends WorkerProcessor {
{
delay: INVOICE.INVOICE_REMINDER_REPEAT_DELAY, // 1 day delay in milliseconds
attempts: INVOICE.INVOICE_REMINDER_JOB_ATTEMPTS,
backoff: INVOICE.INVOICE_REMINDER_JOB_BACKOFF,
backoff: { type: "exponential", delay: INVOICE.INVOICE_REMINDER_JOB_BACKOFF },
},
);
}
@@ -261,7 +262,7 @@ export class InvoiceProcessor extends WorkerProcessor {
};
await Promise.all(
admins.map((admin) => this.notificationService.createRucurringInvoiceNotification(admin.id, notificationPayload, queryRunner)),
admins.map((admin) => this.notificationService.createRecurringInvoiceNotification(admin.id, notificationPayload, queryRunner)),
);
}
}
+9
View File
@@ -0,0 +1,9 @@
import { Module } from "@nestjs/common";
import { LoggerService } from "./logger.service";
@Module({
providers: [LoggerService],
exports: [LoggerService],
})
export class LoggerModule {}
+43
View File
@@ -0,0 +1,43 @@
import { Injectable, Logger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { InjectBot } from "nestjs-telegraf";
import { Telegraf } from "telegraf";
@Injectable()
export class LoggerService extends Logger {
private chatId: string;
constructor(
@InjectBot() private bot: Telegraf,
private configService: ConfigService,
) {
super();
this.chatId = this.configService.getOrThrow<string>("TELEGRAM_CHAT_ID");
}
async sendLogToTelegram(level: string, message: string) {
try {
const logMessage = `🚨 *${level.toUpperCase()} Log:*\n${message}`;
await this.bot.telegram.sendMessage(this.chatId, logMessage, {
parse_mode: "Markdown",
});
} catch (error) {
super.error(`Failed to send log to Telegram:`, error);
}
}
override log(message: any) {
this.sendLogToTelegram("test", message);
super.log(message);
}
override error(message: any, trace?: any) {
super.error(message, trace);
this.sendLogToTelegram("error", `${message}\nTrace: ${trace}`);
}
override warn(message: any) {
super.warn(message);
this.sendLogToTelegram("warn", message);
}
}
@@ -317,7 +317,7 @@ export class NotificationsService {
// //************************ */
async createRucurringInvoiceNotification(recipientId: string, data: IInvoiceNotificationData, queryRunner: QueryRunner) {
async createRecurringInvoiceNotification(recipientId: string, data: IInvoiceNotificationData, queryRunner: QueryRunner) {
const message = NotificationMessage.RECURRING_INVOICE_MESSAGE.replace("[invoiceNumber]", data.invoiceId);
//sent notification based on the userSettings
const { isActive } = await this.userSettingsService.getUserNotificationSettingWithType(NotifType.RECURRING_INVOICE, recipientId);