Completing ntfy module and adding to other modules
This commit is contained in:
parent
2f7d5c68ef
commit
62a4b8c9e6
12 changed files with 176 additions and 49 deletions
|
|
@ -1,9 +1,12 @@
|
|||
import { BullModule } from '@nestjs/bull'
|
||||
import { Module } from '@nestjs/common'
|
||||
|
||||
import { NtfyClient } from './client'
|
||||
import { NtfyProvider } from './provider'
|
||||
import { NTFY_PUBLISH_QUEUE_NAME } from './types'
|
||||
|
||||
@Module({
|
||||
imports: [BullModule.registerQueue({ name: NTFY_PUBLISH_QUEUE_NAME })],
|
||||
providers: [NtfyProvider, NtfyClient],
|
||||
exports: [NtfyProvider, NtfyClient],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,38 +1,113 @@
|
|||
import { InjectQueue, Process, Processor } from '@nestjs/bull'
|
||||
import { Inject, Injectable } from '@nestjs/common'
|
||||
import { Job, JobOptions, Queue } from 'bull'
|
||||
import { Dayjs } from 'dayjs'
|
||||
|
||||
import { NtfyClient } from './client'
|
||||
import { MessagePriority, MessageTags } from './types'
|
||||
import {
|
||||
MessageConfig,
|
||||
MessagePriority,
|
||||
MessageTags,
|
||||
NTFY_PUBLISH_QUEUE_NAME,
|
||||
} from './types'
|
||||
|
||||
@Processor(NTFY_PUBLISH_QUEUE_NAME)
|
||||
@Injectable()
|
||||
export class NtfyProvider {
|
||||
constructor(
|
||||
@Inject(NtfyClient)
|
||||
private readonly ntfyClient: NtfyClient,
|
||||
|
||||
@InjectQueue(NTFY_PUBLISH_QUEUE_NAME)
|
||||
private readonly publishQueue: Queue,
|
||||
) {}
|
||||
|
||||
async sendErrorNotification(
|
||||
title: string,
|
||||
message: string,
|
||||
priority = MessagePriority.default,
|
||||
) {
|
||||
@Process()
|
||||
async handlePublishJob(job: Job<Omit<MessageConfig, 'topic'>>) {
|
||||
await this.ntfyClient.publish({
|
||||
title,
|
||||
message,
|
||||
tags: [MessageTags.red_x],
|
||||
priority,
|
||||
...job.data,
|
||||
})
|
||||
}
|
||||
|
||||
async sendInfoNotification(
|
||||
title: string,
|
||||
message: string,
|
||||
priority = MessagePriority.low,
|
||||
) {
|
||||
await this.ntfyClient.publish({
|
||||
private static defaultJob(
|
||||
data: Omit<MessageConfig, 'topic'>,
|
||||
): [Omit<MessageConfig, 'topic'>, JobOptions] {
|
||||
return [
|
||||
data,
|
||||
{
|
||||
attempts: 3,
|
||||
removeOnComplete: true,
|
||||
backoff: {
|
||||
type: 'exponential',
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
async sendCronStartNotification(title: string) {
|
||||
await this.publishQueue.add(
|
||||
...NtfyProvider.defaultJob({
|
||||
title,
|
||||
tags: [MessageTags.alarm_clock, MessageTags.green_circle],
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
async sendCronStopNotification(title: string, message: string) {
|
||||
await this.publishQueue.add(
|
||||
...NtfyProvider.defaultJob({
|
||||
title,
|
||||
message,
|
||||
tags: [MessageTags.info],
|
||||
priority,
|
||||
})
|
||||
tags: [MessageTags.alarm_clock, MessageTags.red_circle],
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
async sendPerformingReservationNotification(
|
||||
reservationId: string,
|
||||
startTime: Dayjs,
|
||||
endTime: Dayjs,
|
||||
) {
|
||||
await this.publishQueue.add(
|
||||
...NtfyProvider.defaultJob({
|
||||
title: 'Performing reservation',
|
||||
message: `${reservationId} - ${startTime.format()} to ${endTime.format()}`,
|
||||
tags: [MessageTags.badminton],
|
||||
priority: MessagePriority.low,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
async sendErrorPerformingReservationNotification(
|
||||
reservationId: string,
|
||||
startTime: Dayjs,
|
||||
endTime: Dayjs,
|
||||
error: Error,
|
||||
) {
|
||||
await this.publishQueue.add(
|
||||
...NtfyProvider.defaultJob({
|
||||
title: 'Error performing reservation',
|
||||
message: `${reservationId} - ${startTime.format()} to ${endTime.format()} : (${
|
||||
error.name
|
||||
}) - ${error.message}`,
|
||||
tags: [MessageTags.badminton, MessageTags.red_x],
|
||||
priority: MessagePriority.low,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
async sendReservationWaitlistedNotification(
|
||||
reservationId: string,
|
||||
startTime: Dayjs,
|
||||
endTime: Dayjs,
|
||||
) {
|
||||
await this.publishQueue.add(
|
||||
...NtfyProvider.defaultJob({
|
||||
title: 'Reservation waitlisted',
|
||||
message: `${reservationId} - ${startTime.format()} to ${endTime.format()}`,
|
||||
tags: [MessageTags.badminton, MessageTags.hourglass],
|
||||
priority: MessagePriority.low,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,29 @@
|
|||
export const NTFY_PUBLISH_QUEUE_NAME = 'ntfy_publish_queue'
|
||||
|
||||
export enum MessageTags {
|
||||
thumbs_up = '+1',
|
||||
thumbs_down = '-1',
|
||||
alarm_clock = 'alarm_clock',
|
||||
green_circle = 'green_circle',
|
||||
yellow_circle = 'yellow_circle',
|
||||
red_circle = 'red_circle',
|
||||
info = 'information_source',
|
||||
hourglass = 'hourglass',
|
||||
warning = 'warning',
|
||||
rotating_light = 'rotating-light',
|
||||
skull_and_crossbones = 'skull_and_crossbones',
|
||||
tada = 'tada',
|
||||
outbox_tray = 'outbox_tray',
|
||||
inbox_tray = 'inbox_tray',
|
||||
date = 'date',
|
||||
no_entry = 'no_entry',
|
||||
exclamation = 'exclamation',
|
||||
question = 'question',
|
||||
no_entry = 'no_entry',
|
||||
white_check_mark = 'white_check_mark',
|
||||
red_x = 'x',
|
||||
zero = 'zero',
|
||||
one = 'zero',
|
||||
two = 'zero',
|
||||
three = 'zero',
|
||||
four = 'zero',
|
||||
five = 'zero',
|
||||
six = 'zero',
|
||||
seven = 'zero',
|
||||
eight = 'zero',
|
||||
nine = 'zero',
|
||||
one = 'one',
|
||||
two = 'two',
|
||||
three = 'three',
|
||||
four = 'four',
|
||||
five = 'five',
|
||||
six = 'six',
|
||||
seven = 'seven',
|
||||
eight = 'eight',
|
||||
nine = 'nine',
|
||||
new = 'new',
|
||||
ok = 'ok',
|
||||
sos = 'sos',
|
||||
clock12 = 'clock12',
|
||||
clock1230 = 'clock1230',
|
||||
clock1 = 'clock1',
|
||||
|
|
@ -51,7 +49,6 @@ export enum MessageTags {
|
|||
clock11 = 'clock11',
|
||||
clock1130 = 'clock1130',
|
||||
badminton = 'badminton',
|
||||
info = 'information_source',
|
||||
}
|
||||
|
||||
export enum MessagePriority {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Cron, CronExpression } from '@nestjs/schedule'
|
|||
|
||||
import dayjs from '../common/dayjs'
|
||||
import { LoggerService } from '../logger/service.logger'
|
||||
import { NtfyProvider } from '../ntfy/provider'
|
||||
import { RecurringReservationsService } from './service'
|
||||
|
||||
@Injectable()
|
||||
|
|
@ -13,6 +14,9 @@ export class RecurringReservationsCronService {
|
|||
|
||||
@Inject(LoggerService)
|
||||
private readonly loggerService: LoggerService,
|
||||
|
||||
@Inject(NtfyProvider)
|
||||
private readonly ntfyProvider: NtfyProvider,
|
||||
) {}
|
||||
|
||||
@Cron(CronExpression.EVERY_DAY_AT_4AM, {
|
||||
|
|
@ -21,6 +25,9 @@ export class RecurringReservationsCronService {
|
|||
})
|
||||
async handleRecurringReservations() {
|
||||
this.loggerService.log('handleRecurringReservations beginning')
|
||||
await this.ntfyProvider.sendCronStartNotification(
|
||||
'handleRecurringReservations',
|
||||
)
|
||||
const dayOfWeek = dayjs().get('day')
|
||||
const recurringReservationsToSchedule =
|
||||
await this.recurringReservationsService.getByDayOfWeek(dayOfWeek)
|
||||
|
|
@ -33,5 +40,9 @@ export class RecurringReservationsCronService {
|
|||
)
|
||||
}
|
||||
this.loggerService.log('handleRecurringReservations ending')
|
||||
await this.ntfyProvider.sendCronStopNotification(
|
||||
'handleRecurringReservations',
|
||||
`Count: ${recurringReservationsToSchedule.length}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { Module } from '@nestjs/common'
|
||||
import { TypeOrmModule } from '@nestjs/typeorm'
|
||||
import { ReservationsModule } from 'src/reservations/module'
|
||||
|
||||
import { LoggerModule } from '../logger/module'
|
||||
import { NtfyModule } from '../ntfy/module'
|
||||
import { ReservationsModule } from '../reservations/module'
|
||||
import { RunnerModule } from '../runner/module'
|
||||
import { RecurringReservationsController } from './controller'
|
||||
import { RecurringReservationsCronService } from './cron'
|
||||
|
|
@ -15,6 +16,7 @@ import { RecurringReservationsService } from './service'
|
|||
TypeOrmModule.forFeature([RecurringReservation]),
|
||||
RunnerModule,
|
||||
ReservationsModule,
|
||||
NtfyModule,
|
||||
],
|
||||
controllers: [RecurringReservationsController],
|
||||
providers: [RecurringReservationsService, RecurringReservationsCronService],
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export class RecurringReservationsService {
|
|||
constructor(
|
||||
@InjectRepository(RecurringReservation)
|
||||
private recurringReservationsRepository: Repository<RecurringReservation>,
|
||||
|
||||
@Inject(ReservationsService)
|
||||
private reservationsService: ReservationsService,
|
||||
) {}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Cron, CronExpression } from '@nestjs/schedule'
|
|||
import { Queue } from 'bull'
|
||||
|
||||
import { LoggerService } from '../logger/service.logger'
|
||||
import { NtfyProvider } from '../ntfy/provider'
|
||||
import { RESERVATIONS_QUEUE_NAME } from './config'
|
||||
import { ReservationsService } from './service'
|
||||
|
||||
|
|
@ -16,6 +17,9 @@ export class ReservationsCronService {
|
|||
@InjectQueue(RESERVATIONS_QUEUE_NAME)
|
||||
private readonly reservationsQueue: Queue,
|
||||
|
||||
@Inject(NtfyProvider)
|
||||
private readonly ntfyProvider: NtfyProvider,
|
||||
|
||||
@Inject(LoggerService)
|
||||
private readonly loggerService: LoggerService,
|
||||
) {}
|
||||
|
|
@ -26,6 +30,7 @@ export class ReservationsCronService {
|
|||
})
|
||||
async handleDailyReservations() {
|
||||
this.loggerService.log('handleDailyReservations beginning')
|
||||
await this.ntfyProvider.sendCronStartNotification('handleDailyReservations')
|
||||
const reservationsToPerform = await this.reservationService.getSchedulable()
|
||||
this.loggerService.log(
|
||||
`Found ${reservationsToPerform.length} reservations to perform`,
|
||||
|
|
@ -34,6 +39,10 @@ export class ReservationsCronService {
|
|||
reservationsToPerform.map((r) => ({ data: r, opts: { attempts: 1 } })),
|
||||
)
|
||||
this.loggerService.log('handleDailyReservations ending')
|
||||
await this.ntfyProvider.sendCronStopNotification(
|
||||
'handleDailyReservations',
|
||||
`Count: ${reservationsToPerform.length}`,
|
||||
)
|
||||
}
|
||||
|
||||
@Cron(CronExpression.EVERY_DAY_AT_11PM, {
|
||||
|
|
@ -42,6 +51,9 @@ export class ReservationsCronService {
|
|||
})
|
||||
async cleanUpExpiredReservations() {
|
||||
this.loggerService.log('cleanUpExpiredReservations beginning')
|
||||
await this.ntfyProvider.sendCronStartNotification(
|
||||
'cleanUpExpiredReservations',
|
||||
)
|
||||
const reservations = await this.reservationService.getByDate()
|
||||
this.loggerService.log(
|
||||
`Found ${reservations.length} reservations to delete`,
|
||||
|
|
@ -50,5 +62,9 @@ export class ReservationsCronService {
|
|||
await this.reservationService.deleteById(reservation.id)
|
||||
}
|
||||
this.loggerService.log('cleanUpExpiredReservations ending')
|
||||
await this.ntfyProvider.sendCronStopNotification(
|
||||
'cleanUpExpiredReservations',
|
||||
`Count: ${reservations.length}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Module } from '@nestjs/common'
|
|||
import { TypeOrmModule } from '@nestjs/typeorm'
|
||||
|
||||
import { LoggerModule } from '../logger/module'
|
||||
import { NtfyModule } from '../ntfy/module'
|
||||
import { RunnerModule } from '../runner/module'
|
||||
import { RESERVATIONS_QUEUE_NAME } from './config'
|
||||
import { ReservationsController } from './controller'
|
||||
|
|
@ -17,6 +18,7 @@ import { ReservationsWorker } from './worker'
|
|||
TypeOrmModule.forFeature([Reservation]),
|
||||
BullModule.registerQueue({ name: RESERVATIONS_QUEUE_NAME }),
|
||||
RunnerModule,
|
||||
NtfyModule,
|
||||
],
|
||||
exports: [ReservationsService],
|
||||
controllers: [ReservationsController],
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Job } from 'bull'
|
|||
import { instanceToPlain, plainToInstance } from 'class-transformer'
|
||||
|
||||
import { LoggerService } from '../logger/service.logger'
|
||||
import { NtfyProvider } from '../ntfy/provider'
|
||||
import {
|
||||
BaanReserverenService,
|
||||
NoCourtAvailableError,
|
||||
|
|
@ -23,6 +24,9 @@ export class ReservationsWorker {
|
|||
|
||||
@Inject(LoggerService)
|
||||
private readonly loggerService: LoggerService,
|
||||
|
||||
@Inject(NtfyProvider)
|
||||
private readonly ntfyProvider: NtfyProvider,
|
||||
) {}
|
||||
|
||||
@Process()
|
||||
|
|
@ -33,11 +37,16 @@ export class ReservationsWorker {
|
|||
this.loggerService.log('Handling reservation', {
|
||||
reservation: instanceToPlain(reservation),
|
||||
})
|
||||
await this.ntfyProvider.sendPerformingReservationNotification(
|
||||
reservation.id,
|
||||
reservation.dateRangeStart,
|
||||
reservation.dateRangeEnd,
|
||||
)
|
||||
await this.performReservation(reservation)
|
||||
}
|
||||
|
||||
private async handleReservationErrors(
|
||||
error: unknown,
|
||||
error: Error,
|
||||
reservation: Reservation,
|
||||
) {
|
||||
switch (true) {
|
||||
|
|
@ -45,12 +54,23 @@ export class ReservationsWorker {
|
|||
this.loggerService.warn('No court available')
|
||||
if (!reservation.waitListed) {
|
||||
this.loggerService.log('Adding reservation to waiting list')
|
||||
await this.ntfyProvider.sendReservationWaitlistedNotification(
|
||||
reservation.id,
|
||||
reservation.dateRangeStart,
|
||||
reservation.dateRangeEnd,
|
||||
)
|
||||
await this.addReservationToWaitList(reservation)
|
||||
}
|
||||
return
|
||||
}
|
||||
default:
|
||||
this.loggerService.error('Error while performing reservation', error)
|
||||
this.ntfyProvider.sendErrorPerformingReservationNotification(
|
||||
reservation.id,
|
||||
reservation.dateRangeStart,
|
||||
reservation.dateRangeEnd,
|
||||
error,
|
||||
)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +80,7 @@ export class ReservationsWorker {
|
|||
await this.brService.performReservation(reservation)
|
||||
await this.reservationsService.deleteById(reservation.id)
|
||||
} catch (error: unknown) {
|
||||
await this.handleReservationErrors(error, reservation)
|
||||
await this.handleReservationErrors(error as Error, reservation)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import { Inject, Injectable } from '@nestjs/common'
|
|||
import { instanceToPlain } from 'class-transformer'
|
||||
import { Dayjs } from 'dayjs'
|
||||
import { ElementHandle, Page } from 'puppeteer'
|
||||
import { LoggerService } from 'src/logger/service.logger'
|
||||
|
||||
import dayjs from '../../common/dayjs'
|
||||
import { LoggerService } from '../../logger/service.logger'
|
||||
import { Reservation } from '../../reservations/entity'
|
||||
import { EmptyPage } from '../pages/empty'
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { BullModule } from '@nestjs/bull'
|
||||
import { Module } from '@nestjs/common'
|
||||
import { EmailModule } from 'src/email/module'
|
||||
import { ReservationsModule } from 'src/reservations/module'
|
||||
|
||||
import { EMAILS_QUEUE_NAME } from '../email/config'
|
||||
import { EmailModule } from '../email/module'
|
||||
import { LoggerModule } from '../logger/module'
|
||||
import { RESERVATIONS_QUEUE_NAME } from '../reservations/config'
|
||||
import { ReservationsModule } from '../reservations/module'
|
||||
import { WaitingListService } from './service'
|
||||
|
||||
@Module({
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { InjectQueue, Process, Processor } from '@nestjs/bull'
|
||||
import { Inject } from '@nestjs/common'
|
||||
import { Job, Queue } from 'bull'
|
||||
import { EmailProvider } from 'src/email/provider'
|
||||
import { ReservationsService } from 'src/reservations/service'
|
||||
|
||||
import dayjs from '../common/dayjs'
|
||||
import { EMAILS_QUEUE_NAME } from '../email/config'
|
||||
import { EmailProvider } from '../email/provider'
|
||||
import { Email } from '../email/types'
|
||||
import { LoggerService } from '../logger/service.logger'
|
||||
import { RESERVATIONS_QUEUE_NAME } from '../reservations/config'
|
||||
import { ReservationsService } from '../reservations/service'
|
||||
import { WaitingListDetails } from './types'
|
||||
|
||||
const EMAIL_SUBJECT_REGEX = new RegExp(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue