autobaan/src/reservations/worker.ts

126 lines
3.2 KiB
TypeScript
Raw Normal View History

import { Process, Processor } from '@nestjs/bull'
import { Inject } from '@nestjs/common'
import { Job } from 'bull'
import { instanceToPlain, plainToInstance } from 'class-transformer'
import { LoggerService } from '../logger/service.logger'
import { NtfyProvider } from '../ntfy/provider'
import {
BaanReserverenService,
NoCourtAvailableError,
} from '../runner/baanreserveren/service'
import { RESERVATIONS_QUEUE_NAME, ReservationsJob } from './config'
2024-03-12 13:02:45 +01:00
import { DAILY_RESERVATIONS_ATTEMPTS } from './cron'
import { Reservation } from './entity'
import { ReservationsService } from './service'
@Processor(RESERVATIONS_QUEUE_NAME)
export class ReservationsWorker {
2023-06-27 16:06:19 +02:00
constructor(
@Inject(BaanReserverenService)
private readonly brService: BaanReserverenService,
@Inject(ReservationsService)
private readonly reservationsService: ReservationsService,
2023-06-27 16:06:19 +02:00
@Inject(LoggerService)
2023-07-29 14:58:48 +02:00
private readonly loggerService: LoggerService,
@Inject(NtfyProvider)
private readonly ntfyProvider: NtfyProvider,
2023-06-27 16:06:19 +02:00
) {}
2023-06-27 16:06:19 +02:00
@Process()
async handleReservationJob(job: ReservationsJob) {
const reservation = plainToInstance(Reservation, job.data.reservation, {
2023-06-27 16:06:19 +02:00
groups: ['password'],
})
2023-07-29 14:58:48 +02:00
this.loggerService.log('Handling reservation', {
2023-06-27 16:06:19 +02:00
reservation: instanceToPlain(reservation),
})
await this.ntfyProvider.sendPerformingReservationNotification(
reservation.id,
reservation.dateRangeStart,
reservation.dateRangeEnd,
)
await this.performReservation(
reservation,
job.attemptsMade,
true,
job.data.speedyMode,
)
2023-06-27 16:06:19 +02:00
}
private async handleReservationErrors(
error: Error,
reservation: Reservation,
attemptsMade: number,
timeSensitive = true,
) {
const shouldWaitlist = error instanceof NoCourtAvailableError
if (shouldWaitlist) {
this.loggerService.warn('No court available')
} else {
this.loggerService.error('Error while performing reservation', error)
}
if (
(shouldWaitlist || attemptsMade === DAILY_RESERVATIONS_ATTEMPTS) &&
!reservation.waitListed
) {
this.loggerService.log('Adding reservation to waiting list')
await this.ntfyProvider.sendReservationWaitlistedNotification(
reservation.id,
reservation.dateRangeStart,
reservation.dateRangeEnd,
)
await this.addReservationToWaitList(reservation, timeSensitive)
} else {
throw error
}
}
async performReservation(
reservation: Reservation,
attemptsMade: number,
timeSensitive = true,
2024-04-30 10:27:10 +02:00
speedyMode = true,
) {
try {
2024-04-30 10:27:10 +02:00
if (speedyMode) {
await this.brService.performSpeedyReservation(reservation)
} else {
await this.brService.performReservation(reservation, timeSensitive)
}
await this.reservationsService.deleteById(reservation.id)
} catch (error: unknown) {
await this.handleReservationErrors(
error as Error,
reservation,
attemptsMade,
timeSensitive,
)
}
}
async addReservationToWaitList(
reservation: Reservation,
timeSensitive = true,
) {
try {
const waitingListId = await this.brService.addReservationToWaitList(
reservation,
timeSensitive,
)
await this.reservationsService.update(reservation.id, {
waitListed: true,
waitingListId,
})
} catch (error: unknown) {
this.loggerService.error(
'Error adding reservation to waiting list',
error,
)
}
2023-06-27 16:06:19 +02:00
}
}