2023-05-26 15:43:14 -05:00
|
|
|
import { Process, Processor } from '@nestjs/bull'
|
2023-06-29 10:32:09 +02:00
|
|
|
import { Inject } from '@nestjs/common'
|
2023-05-26 15:43:14 -05:00
|
|
|
import { Job } from 'bull'
|
|
|
|
|
import { instanceToPlain, plainToInstance } from 'class-transformer'
|
2023-06-29 10:32:09 +02:00
|
|
|
|
2023-08-29 10:44:12 +02:00
|
|
|
import { LoggerService } from '../logger/service.logger'
|
2023-09-06 11:23:21 +02:00
|
|
|
import { NtfyProvider } from '../ntfy/provider'
|
2023-07-28 19:50:04 +02:00
|
|
|
import {
|
|
|
|
|
BaanReserverenService,
|
|
|
|
|
NoCourtAvailableError,
|
|
|
|
|
} from '../runner/baanreserveren/service'
|
2023-05-26 15:43:14 -05:00
|
|
|
import { RESERVATIONS_QUEUE_NAME } from './config'
|
2024-03-12 13:02:45 +01:00
|
|
|
import { DAILY_RESERVATIONS_ATTEMPTS } from './cron'
|
2023-05-26 15:43:14 -05:00
|
|
|
import { Reservation } from './entity'
|
2023-07-29 15:23:04 +02:00
|
|
|
import { ReservationsService } from './service'
|
2023-05-26 15:43:14 -05:00
|
|
|
|
|
|
|
|
@Processor(RESERVATIONS_QUEUE_NAME)
|
|
|
|
|
export class ReservationsWorker {
|
2023-06-27 16:06:19 +02:00
|
|
|
constructor(
|
|
|
|
|
@Inject(BaanReserverenService)
|
|
|
|
|
private readonly brService: BaanReserverenService,
|
2023-05-26 15:43:14 -05:00
|
|
|
|
2023-07-29 15:23:04 +02:00
|
|
|
@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,
|
2023-09-06 11:23:21 +02:00
|
|
|
|
|
|
|
|
@Inject(NtfyProvider)
|
|
|
|
|
private readonly ntfyProvider: NtfyProvider,
|
2023-06-27 16:06:19 +02:00
|
|
|
) {}
|
2023-05-26 15:43:14 -05:00
|
|
|
|
2023-06-27 16:06:19 +02:00
|
|
|
@Process()
|
|
|
|
|
async handleReservationJob(job: Job<Reservation>) {
|
|
|
|
|
const reservation = plainToInstance(Reservation, job.data, {
|
|
|
|
|
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),
|
|
|
|
|
})
|
2023-09-06 11:23:21 +02:00
|
|
|
await this.ntfyProvider.sendPerformingReservationNotification(
|
|
|
|
|
reservation.id,
|
|
|
|
|
reservation.dateRangeStart,
|
|
|
|
|
reservation.dateRangeEnd,
|
|
|
|
|
)
|
2024-04-11 11:46:25 +02:00
|
|
|
await this.performReservation(reservation, job.attemptsMade, false)
|
2023-06-27 16:06:19 +02:00
|
|
|
}
|
2023-05-26 15:43:14 -05:00
|
|
|
|
2023-07-28 19:50:04 +02:00
|
|
|
private async handleReservationErrors(
|
2023-09-06 11:23:21 +02:00
|
|
|
error: Error,
|
2023-07-28 19:50:04 +02:00
|
|
|
reservation: Reservation,
|
2024-02-23 07:35:35 -06:00
|
|
|
attemptsMade: number,
|
2024-04-11 11:46:25 +02:00
|
|
|
timeSensitive = true,
|
2023-07-28 19:50:04 +02:00
|
|
|
) {
|
2024-03-20 20:43:37 +01:00
|
|
|
const shouldWaitlist = error instanceof NoCourtAvailableError
|
|
|
|
|
if (shouldWaitlist) {
|
2024-02-23 07:35:35 -06:00
|
|
|
this.loggerService.warn('No court available')
|
2024-03-20 20:43:37 +01:00
|
|
|
} else {
|
|
|
|
|
this.loggerService.error('Error while performing reservation', error)
|
2024-02-23 07:35:35 -06:00
|
|
|
}
|
|
|
|
|
if (
|
2024-03-20 20:43:37 +01:00
|
|
|
(shouldWaitlist || attemptsMade === DAILY_RESERVATIONS_ATTEMPTS) &&
|
2024-02-23 07:35:35 -06:00
|
|
|
!reservation.waitListed
|
|
|
|
|
) {
|
|
|
|
|
this.loggerService.log('Adding reservation to waiting list')
|
|
|
|
|
await this.ntfyProvider.sendReservationWaitlistedNotification(
|
|
|
|
|
reservation.id,
|
|
|
|
|
reservation.dateRangeStart,
|
|
|
|
|
reservation.dateRangeEnd,
|
|
|
|
|
)
|
2024-04-11 11:46:25 +02:00
|
|
|
await this.addReservationToWaitList(reservation, timeSensitive)
|
2024-03-20 20:43:37 +01:00
|
|
|
} else {
|
|
|
|
|
throw error
|
2023-07-28 19:50:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-11 11:46:25 +02:00
|
|
|
async performReservation(
|
|
|
|
|
reservation: Reservation,
|
|
|
|
|
attemptsMade: number,
|
|
|
|
|
timeSensitive = true,
|
|
|
|
|
) {
|
2023-07-28 19:50:04 +02:00
|
|
|
try {
|
|
|
|
|
await this.brService.performReservation(reservation)
|
2023-07-29 15:23:04 +02:00
|
|
|
await this.reservationsService.deleteById(reservation.id)
|
2023-07-28 19:50:04 +02:00
|
|
|
} catch (error: unknown) {
|
2024-02-23 07:35:35 -06:00
|
|
|
await this.handleReservationErrors(
|
|
|
|
|
error as Error,
|
|
|
|
|
reservation,
|
|
|
|
|
attemptsMade,
|
2024-04-11 11:46:25 +02:00
|
|
|
timeSensitive,
|
2024-02-23 07:35:35 -06:00
|
|
|
)
|
2023-07-28 19:50:04 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-11 11:46:25 +02:00
|
|
|
async addReservationToWaitList(
|
|
|
|
|
reservation: Reservation,
|
|
|
|
|
timeSensitive = true,
|
|
|
|
|
) {
|
2023-07-31 15:18:08 +02:00
|
|
|
try {
|
2023-08-31 11:30:15 +02:00
|
|
|
const waitingListId = await this.brService.addReservationToWaitList(
|
|
|
|
|
reservation,
|
2024-04-11 11:46:25 +02:00
|
|
|
timeSensitive,
|
2023-08-31 11:30:15 +02:00
|
|
|
)
|
2023-07-31 15:18:08 +02:00
|
|
|
await this.reservationsService.update(reservation.id, {
|
|
|
|
|
waitListed: true,
|
2023-08-31 11:30:15 +02:00
|
|
|
waitingListId,
|
2023-07-31 15:18:08 +02:00
|
|
|
})
|
|
|
|
|
} catch (error: unknown) {
|
2023-08-10 13:34:39 +02:00
|
|
|
this.loggerService.error(
|
|
|
|
|
'Error adding reservation to waiting list',
|
2023-07-31 15:18:08 +02:00
|
|
|
error,
|
2023-08-10 13:34:39 +02:00
|
|
|
)
|
2023-07-31 15:18:08 +02:00
|
|
|
}
|
2023-06-27 16:06:19 +02:00
|
|
|
}
|
|
|
|
|
}
|