@@ -4,15 +4,18 @@ import { Cron, SchedulerRegistry } from '@nestjs/schedule';
44import { CronJob } from 'cron' ;
55import Redis from 'ioredis' ;
66
7+ import { AuthService } from '../../../auth/service/auth.service' ;
78import { Event } from '../../event/entity/event.entity' ;
89import { EventRepository } from '../../event/repository/event.reposiotry' ;
910import { SectionRepository } from '../../place/repository/section.repository' ;
11+ import { UserService } from '../../user/service/user.service' ;
1012import { ONE_MINUTE_BEFORE_THE_HOUR } from '../const/cronExpressions.const' ;
1113import { IN_BOOKING_DEFAULT_MAX_SIZE } from '../const/inBookingDefaultMaxSize.const' ;
1214
1315import { BookingSeatsService } from './booking-seats.service' ;
1416import { EnterBookingService } from './enter-booking.service' ;
1517import { InBookingService } from './in-booking.service' ;
18+ import { WaitingQueueService } from './waiting-queue.service' ;
1619
1720@Injectable ( )
1821export class OpenBookingService implements OnApplicationBootstrap {
@@ -22,8 +25,11 @@ export class OpenBookingService implements OnApplicationBootstrap {
2225 private redisService : RedisService ,
2326 private eventRepository : EventRepository ,
2427 private sectionRepository : SectionRepository ,
28+ private authService : AuthService ,
29+ private userService : UserService ,
2530 private inBookingService : InBookingService ,
2631 private seatsUpdateService : BookingSeatsService ,
32+ private waitingQueueService : WaitingQueueService ,
2733 private enterBookingService : EnterBookingService ,
2834 private schedulerRegistry : SchedulerRegistry ,
2935 ) {
@@ -38,21 +44,35 @@ export class OpenBookingService implements OnApplicationBootstrap {
3844 @Cron ( ONE_MINUTE_BEFORE_THE_HOUR )
3945 async scheduleUpcomingReservations ( ) {
4046 const comingEvents = await this . eventRepository . selectUpcomingEvents ( ) ;
41- const openedEventIds = new Set ( await this . getOpenedEventIds ( ) ) ;
47+ await this . scheduleUpcomingReservationsToOpen ( comingEvents ) ;
48+ await this . scheduleUpcomingReservationsToClose ( comingEvents ) ;
49+ }
50+
51+ private async scheduleUpcomingReservationsToOpen ( comingEvents : Event [ ] ) {
4252 const now = new Date ( ) ;
53+ const openedEventIds = new Set ( await this . getOpenedEventIds ( ) ) ;
4354 const eventToOpen = comingEvents . filter ( ( event ) => event . reservationOpenDate <= now ) ;
44- const eventsToSchedule = comingEvents . filter (
55+ const eventsToScheduleOpen = comingEvents . filter (
4556 ( event ) => ! openedEventIds . has ( event . id ) && event . reservationOpenDate > now ,
4657 ) ;
4758
4859 for ( const event of eventToOpen ) {
4960 await this . openReservation ( event ) ;
5061 }
51- for ( const event of eventsToSchedule ) {
62+ for ( const event of eventsToScheduleOpen ) {
5263 this . scheduleReservationOpen ( event ) ;
5364 }
5465 }
5566
67+ private async scheduleUpcomingReservationsToClose ( comingEvents : Event [ ] ) {
68+ const now = new Date ( ) ;
69+ const eventsToScheduleClose = comingEvents . filter ( ( event ) => event . reservationCloseDate > now ) ;
70+
71+ for ( const event of eventsToScheduleClose ) {
72+ this . scheduleReservationClose ( event ) ;
73+ }
74+ }
75+
5676 private scheduleReservationOpen ( event : Event ) {
5777 const jobName = `reservation-open-${ event . id } ` ;
5878
@@ -68,6 +88,21 @@ export class OpenBookingService implements OnApplicationBootstrap {
6888 job . start ( ) ;
6989 }
7090
91+ private scheduleReservationClose ( event : Event ) {
92+ const jobName = `reservation-close-${ event . id } ` ;
93+
94+ if ( this . schedulerRegistry . doesExist ( 'cron' , jobName ) ) {
95+ this . schedulerRegistry . deleteCronJob ( jobName ) ;
96+ }
97+
98+ const job = new CronJob ( event . reservationCloseDate , async ( ) => {
99+ await this . closeReservation ( event . id ) ;
100+ } ) ;
101+
102+ this . schedulerRegistry . addCronJob ( jobName , job ) ;
103+ job . start ( ) ;
104+ }
105+
71106 async isEventOpened ( eventId : number ) {
72107 return ( await this . redis . get ( `open-booking:${ eventId } :opened` ) ) === 'true' ;
73108 }
@@ -107,22 +142,70 @@ export class OpenBookingService implements OnApplicationBootstrap {
107142 if ( ! event ) {
108143 return false ;
109144 }
110-
111145 const openTime = event . reservationOpenDate ;
112146 if ( openTime > new Date ( ) ) {
113- const jobName = `reservation-open-${ event . id } ` ;
114- const job = new CronJob ( openTime , async ( ) => {
115- await this . openReservationById ( event . id ) ;
116- } ) ;
117- this . schedulerRegistry . addCronJob ( jobName , job ) ;
118- job . start ( ) ;
147+ this . scheduleReservationOpen ( event ) ;
119148 return false ;
120149 }
121-
122150 return true ;
123151 }
124152
125153 private async registerOpenedEvent ( eventId : number ) {
126154 await this . redis . set ( `open-booking:${ eventId } :opened` , 'true' ) ;
127155 }
156+
157+ async closeReservation ( eventId : number ) {
158+ await this . validateClosingEvent ( eventId ) ;
159+ await this . unlinkOpenedEvent ( eventId ) ;
160+ await this . clearWaitingService ( eventId ) ;
161+ await this . clearEnteringService ( eventId ) ;
162+ await this . seatsUpdateService . clearSeatsSubscription ( eventId ) ;
163+ await this . clearInBookingService ( eventId ) ;
164+ }
165+
166+ private async validateClosingEvent ( eventId : number ) {
167+ const event = await this . eventRepository . selectEvent ( eventId ) ;
168+ if ( ! event ) {
169+ return false ;
170+ }
171+ const closeTime = event . reservationCloseDate ;
172+ if ( closeTime > new Date ( ) ) {
173+ this . scheduleReservationClose ( event ) ;
174+ return false ;
175+ }
176+ return true ;
177+ }
178+
179+ private async clearWaitingService ( eventId : number ) {
180+ const waitingSids = await this . waitingQueueService . getAllWaitingSids ( eventId ) ;
181+ for ( const sid of waitingSids ) {
182+ await this . resetUserStatus ( sid ) ;
183+ }
184+ await this . waitingQueueService . clearQueue ( eventId ) ;
185+ }
186+
187+ private async clearEnteringService ( eventId : number ) {
188+ const enteringSids = await this . enterBookingService . getAllEnteringSids ( eventId ) ;
189+ for ( const sid of enteringSids ) {
190+ await this . resetUserStatus ( sid ) ;
191+ }
192+ await this . enterBookingService . clearEnteringPool ( eventId ) ;
193+ }
194+
195+ private async clearInBookingService ( eventId : number ) {
196+ const inBookingSids = await this . inBookingService . getAllInBookingSids ( eventId ) ;
197+ for ( const sid of inBookingSids ) {
198+ await this . resetUserStatus ( sid ) ;
199+ }
200+ await this . inBookingService . clearInBookingPool ( eventId ) ;
201+ }
202+
203+ private async resetUserStatus ( sid : string ) {
204+ await this . authService . setUserStatusLogin ( sid ) ;
205+ await this . userService . setUserEventTarget ( sid , 0 ) ;
206+ }
207+
208+ private async unlinkOpenedEvent ( eventId : number ) {
209+ await this . redis . unlink ( `open-booking:${ eventId } :opened` ) ;
210+ }
128211}
0 commit comments