@@ -43,7 +43,9 @@ export class GhostModeReminderCronJob {
4343 template : "ghostmode-reminder" ,
4444 context : {
4545 firstName : user . firstName ,
46- intervalHour : this . i18n . t ( intervalHour . translationKey ) ,
46+ intervalHour : this . i18n . t ( intervalHour . translationKey , {
47+ lang,
48+ } ) ,
4749 t : ( key : string , params ?: Record < string , any > ) =>
4850 this . i18n . translate (
4951 `main.email.ghostmode-reminder.${ key } ` ,
@@ -59,16 +61,20 @@ export class GhostModeReminderCronJob {
5961 const now = new Date ( ) ;
6062 const chunks = 100 ; // Process users in chunks to prevent memory overload
6163
62- // Track different reminder intervals
6364 const intervalHours : IntervalHour [ ] = [
6465 { hours : 24 , translationKey : "main.cron.intervalHours.h24" } ,
6566 { hours : 72 , translationKey : "main.cron.intervalHours.h72" } ,
6667 { hours : 336 , translationKey : "main.cron.intervalHours.h336" } , // 14 days * 24 hours
6768 ] ;
6869
6970 const notificationTicketsToSend : OfflineryNotification [ ] = [ ] ;
70- for ( const intervalHour of intervalHours ) {
71+
72+ // Process one interval at a time, from shortest to longest
73+ for ( let i = 0 ; i < intervalHours . length ; i ++ ) {
74+ const intervalHour = intervalHours [ i ] ;
75+ const previousInterval = i > 0 ? intervalHours [ i - 1 ] . hours : 0 ;
7176 let skip = 0 ;
77+
7278 this . logger . debug (
7379 `Checking users for interval ${ intervalHour . hours } h.` ,
7480 ) ;
@@ -78,33 +84,34 @@ export class GhostModeReminderCronJob {
7884 . createQueryBuilder ( "user" )
7985 . where ( "user.dateMode = :mode" , { mode : EDateMode . GHOST } )
8086 . andWhere (
81- "user.lastDateModeChange IS NULL OR user.lastDateModeChange <= :timestamp " ,
87+ "user.lastDateModeChange IS NULL OR user.lastDateModeChange <= :currentInterval " ,
8288 {
83- timestamp : new Date (
89+ currentInterval : new Date (
8490 now . getTime ( ) -
8591 intervalHour . hours * 60 * 60 * 1000 ,
8692 ) ,
8793 } ,
8894 )
95+ // Only get users who haven't been reminded yet or were last reminded before the previous interval
8996 . andWhere (
90- "user.lastDateModeReminderSent IS NULL OR user.lastDateModeReminderSent < :reminderTimestamp " ,
97+ "( user.lastDateModeReminderSent IS NULL OR user.lastDateModeReminderSent <= :previousInterval) " ,
9198 {
92- reminderTimestamp : new Date (
99+ previousInterval : new Date (
93100 now . getTime ( ) -
94- intervalHour . hours * 60 * 60 * 1000 ,
101+ previousInterval * 60 * 60 * 1000 ,
95102 ) ,
96103 } ,
97104 )
98105 . take ( chunks )
99106 . skip ( skip )
100107 . getMany ( ) ;
101108
109+ if ( users . length === 0 ) break ;
110+
102111 this . logger . debug (
103- `Found ${ users . length } users that are to be reminded for interval ${ intervalHour . hours } h.` ,
112+ `Found ${ users . length } users to remind for interval ${ intervalHour . hours } h.` ,
104113 ) ;
105- if ( users . length === 0 ) break ;
106114
107- // Process users in parallel but with concurrency control
108115 await Promise . all (
109116 users . map ( async ( user ) => {
110117 try {
@@ -145,7 +152,6 @@ export class GhostModeReminderCronJob {
145152 ) ;
146153 }
147154
148- // Update last reminder timestamp
149155 await this . userRepository . update ( user . id , {
150156 lastDateModeReminderSent : now ,
151157 } ) ;
@@ -164,6 +170,7 @@ export class GhostModeReminderCronJob {
164170 `Ghostmode reminders sent for ${ intervalHour . hours } h.` ,
165171 ) ;
166172 }
173+
167174 const tickets = await this . notificationService . sendPushNotifications (
168175 notificationTicketsToSend ,
169176 ) ;
0 commit comments