Adding a warmup and changing daily reservations to utilize this warmup + busy loop to be faster in the morning
This commit is contained in:
parent
73b32402d3
commit
e7bff228c6
6 changed files with 86 additions and 52 deletions
|
|
@ -24,6 +24,8 @@ export interface SerializedDateRange {
|
|||
end: string
|
||||
}
|
||||
|
||||
export const setDefaults = () => dayjs.tz.setDefault('Europe/Amsterdam')
|
||||
|
||||
export const convertDateRangeStringToObject = ({
|
||||
start,
|
||||
end,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { NestFactory } from '@nestjs/core'
|
|||
|
||||
import { AppModule } from './app.module'
|
||||
import { CustomResponseTransformInterceptor } from './common/customResponse'
|
||||
import { setDefaults } from './common/dayjs'
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create(AppModule, { abortOnError: false })
|
||||
|
|
@ -12,6 +13,7 @@ async function bootstrap() {
|
|||
app.enableShutdownHooks()
|
||||
app.useGlobalPipes(new ValidationPipe({ transform: true }))
|
||||
app.useGlobalInterceptors(new CustomResponseTransformInterceptor())
|
||||
setDefaults()
|
||||
await app.listen(port, () => console.log(`Listening on port ${port}`))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import { repl } from '@nestjs/core'
|
||||
|
||||
import { AppModule } from './app.module'
|
||||
import { setDefaults } from './common/dayjs'
|
||||
|
||||
async function bootstrap() {
|
||||
setDefaults()
|
||||
await repl(AppModule)
|
||||
}
|
||||
bootstrap()
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export class ReservationsCronService {
|
|||
private readonly loggerService: LoggerService,
|
||||
) {}
|
||||
|
||||
@Cron(CronExpression.EVERY_DAY_AT_7AM, {
|
||||
@Cron('55 06 * * *', {
|
||||
name: 'handleDailyReservations',
|
||||
timeZone: 'Europe/Amsterdam',
|
||||
})
|
||||
|
|
@ -42,12 +42,36 @@ export class ReservationsCronService {
|
|||
this.loggerService.log(
|
||||
`Found ${reservationsToPerform.length} reservations to perform`,
|
||||
)
|
||||
await this.reservationsQueue.addBulk(
|
||||
reservationsToPerform.map((r) => ({
|
||||
data: r,
|
||||
opts: { attempts: DAILY_RESERVATIONS_ATTEMPTS },
|
||||
})),
|
||||
)
|
||||
|
||||
// In order to make sure session is fresh and speed up some shit let's warm him up
|
||||
await this.brService.warmup()
|
||||
|
||||
this.loggerService.log(`Warmed up! Waiting for go-time`)
|
||||
|
||||
let not7AM = true
|
||||
const waitTime = 10
|
||||
const time7AM = dayjs()
|
||||
.set('hour', 7)
|
||||
.set('minute', 0)
|
||||
.set('second', 0)
|
||||
.set('millisecond', 0)
|
||||
|
||||
while (not7AM) {
|
||||
not7AM = time7AM.isBefore(dayjs()) && time7AM.diff(dayjs()) >= waitTime // current time is more than 100ms from 7am
|
||||
if (!not7AM) break
|
||||
await new Promise((res) => setTimeout(res, waitTime)) // wait for waitTime and then try again
|
||||
}
|
||||
|
||||
this.loggerService.log(`It's go-time`)
|
||||
|
||||
for (const res of reservationsToPerform) {
|
||||
await this.brService.performReservation(res).catch(
|
||||
async () =>
|
||||
await this.reservationsQueue.add(res, {
|
||||
attempts: Math.max(DAILY_RESERVATIONS_ATTEMPTS - 1, 1),
|
||||
}),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
this.loggerService.log('Monitoring reservations')
|
||||
await this.brService.monitorCourtReservations(dayjs().add(7, 'day'))
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export class ReservationsService {
|
|||
},
|
||||
)
|
||||
.andWhere(`waitListed = false`)
|
||||
.orderBy('dateRangeStart', 'DESC')
|
||||
.orderBy('dateRangeStart', 'ASC')
|
||||
|
||||
return await query.getMany()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ const CourtRank = {
|
|||
[CourtSlot.Thirteen]: 1, // no one likes upstairs
|
||||
} as const
|
||||
|
||||
const TYPING_DELAY_MS = 5
|
||||
const TYPING_DELAY_MS = 2
|
||||
|
||||
@Injectable()
|
||||
export class BaanReserverenService {
|
||||
|
|
@ -127,23 +127,24 @@ export class BaanReserverenService {
|
|||
)
|
||||
}
|
||||
|
||||
// Check session by going to /reservations to see if we are still logged in via cookies
|
||||
private async checkSession(username: string) {
|
||||
this.loggerService.debug('Checking session', {
|
||||
username,
|
||||
session: this.session,
|
||||
})
|
||||
if (this.page.url().includes(BAAN_RESERVEREN_ROOT_URL)) {
|
||||
// Check session by going to /reservations to see if we are still logged in via cookies
|
||||
await this.navigateToReservations()
|
||||
if (this.page.url().includes('?reason=LOGGED_IN')) {
|
||||
return SessionAction.Login
|
||||
}
|
||||
|
||||
return this.session?.username !== this.username
|
||||
? SessionAction.Logout
|
||||
: SessionAction.NoAction
|
||||
if (!this.page.url().includes(BAAN_RESERVEREN_ROOT_URL)) {
|
||||
await this.navigateToReservations()
|
||||
}
|
||||
return SessionAction.Login
|
||||
|
||||
if (this.page.url().includes('?reason=LOGGED_IN')) {
|
||||
return SessionAction.Login
|
||||
}
|
||||
|
||||
return this.session?.username !== this.username
|
||||
? SessionAction.Logout
|
||||
: SessionAction.NoAction
|
||||
}
|
||||
|
||||
private startSession(username: string) {
|
||||
|
|
@ -202,8 +203,7 @@ export class BaanReserverenService {
|
|||
|
||||
private async init() {
|
||||
this.loggerService.debug('Initializing')
|
||||
await this.page.goto(BAAN_RESERVEREN_ROOT_URL)
|
||||
await this.page.waitForNetworkIdle()
|
||||
await this.navigateToReservations()
|
||||
const action = await this.checkSession(this.username)
|
||||
switch (action) {
|
||||
case SessionAction.Logout:
|
||||
|
|
@ -533,6 +533,37 @@ export class BaanReserverenService {
|
|||
await this.page.waitForNetworkIdle()
|
||||
}
|
||||
|
||||
private async getAllCourtStatuses() {
|
||||
const courts = await this.page.$$('tr > td.slot')
|
||||
const courtStatuses: {
|
||||
courtNumber: string
|
||||
startTime: string
|
||||
status: string
|
||||
duration: string
|
||||
}[] = []
|
||||
for (const court of courts) {
|
||||
const classListObj = await (
|
||||
await court.getProperty('classList')
|
||||
).jsonValue()
|
||||
const classList = Object.values(classListObj)
|
||||
const rClass = classList.filter((cl) => /r-\d{2}/.test(cl))[0]
|
||||
const courtNumber =
|
||||
`${CourtSlotToNumber[rClass.replace(/r-/, '') as CourtSlot]}` ??
|
||||
'unknown court'
|
||||
const startTime = await court
|
||||
.$eval('div.slot-period', (e) => e.innerText.trim())
|
||||
.catch(() => 'unknown')
|
||||
const status = classList.includes('free') ? 'available' : 'unavailable'
|
||||
const courtRowSpan = await (
|
||||
await court.getProperty('rowSpan')
|
||||
).jsonValue()
|
||||
const duration = `${Number(courtRowSpan ?? '0') * 15} minutes`
|
||||
courtStatuses.push({ courtNumber, startTime, status, duration }) //const d = require('dayjs'); await get(BaanReserverenService).monitorCourtReservations(d());
|
||||
}
|
||||
|
||||
return courtStatuses
|
||||
}
|
||||
|
||||
public async performReservation(reservation: Reservation) {
|
||||
try {
|
||||
await this.init()
|
||||
|
|
@ -588,37 +619,6 @@ export class BaanReserverenService {
|
|||
}
|
||||
}
|
||||
|
||||
private async getAllCourtStatuses() {
|
||||
const courts = await this.page.$$('tr > td.slot')
|
||||
const courtStatuses: {
|
||||
courtNumber: string
|
||||
startTime: string
|
||||
status: string
|
||||
duration: string
|
||||
}[] = []
|
||||
for (const court of courts) {
|
||||
const classListObj = await (
|
||||
await court.getProperty('classList')
|
||||
).jsonValue()
|
||||
const classList = Object.values(classListObj)
|
||||
const rClass = classList.filter((cl) => /r-\d{2}/.test(cl))[0]
|
||||
const courtNumber =
|
||||
`${CourtSlotToNumber[rClass.replace(/r-/, '') as CourtSlot]}` ??
|
||||
'unknown court'
|
||||
const startTime = await court
|
||||
.$eval('div.slot-period', (e) => e.innerText.trim())
|
||||
.catch(() => 'unknown')
|
||||
const status = classList.includes('free') ? 'available' : 'unavailable'
|
||||
const courtRowSpan = await (
|
||||
await court.getProperty('rowSpan')
|
||||
).jsonValue()
|
||||
const duration = `${Number(courtRowSpan ?? '0') * 15} minutes`
|
||||
courtStatuses.push({ courtNumber, startTime, status, duration }) //const d = require('dayjs'); await get(BaanReserverenService).monitorCourtReservations(d());
|
||||
}
|
||||
|
||||
return courtStatuses
|
||||
}
|
||||
|
||||
public async monitorCourtReservations(date?: Dayjs, swallowError = true) {
|
||||
try {
|
||||
if (date) {
|
||||
|
|
@ -642,6 +642,10 @@ export class BaanReserverenService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async warmup() {
|
||||
await this.init()
|
||||
}
|
||||
}
|
||||
|
||||
export class RunnerError extends Error {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue