From 81595ce3f6d1948dcf98a2e935fa23d8a59530cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnea=20R=C3=BAn=20Vignisd=C3=B3ttir?= Date: Mon, 4 Nov 2024 15:37:16 +0000 Subject: [PATCH 01/10] move sleep logic from messgeHandler to worker service --- .../notifications/notifications.module.ts | 1 + .../notificationsWorker.service.ts | 27 ---------------- libs/message-queue/src/lib/nest/types.ts | 2 ++ libs/message-queue/src/lib/nest/utils.spec.ts | 32 ++++++++++++++++++- libs/message-queue/src/lib/nest/utils.ts | 22 +++++++++++++ .../src/lib/nest/worker.service.ts | 15 +++++++-- 6 files changed, 69 insertions(+), 30 deletions(-) diff --git a/apps/services/user-notification/src/app/modules/notifications/notifications.module.ts b/apps/services/user-notification/src/app/modules/notifications/notifications.module.ts index 812bdde441be..9b5f92efce51 100644 --- a/apps/services/user-notification/src/app/modules/notifications/notifications.module.ts +++ b/apps/services/user-notification/src/app/modules/notifications/notifications.module.ts @@ -36,6 +36,7 @@ import { MessageProcessorService } from './messageProcessor.service' queue: { name: 'notifications', queueName: environment.mainQueueName, + shouldSleepOutsideWorkingHours: true, deadLetterQueue: { queueName: environment.deadLetterQueueName, }, diff --git a/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.ts b/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.ts index 764593d87619..ff06f31eb6af 100644 --- a/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.ts +++ b/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.ts @@ -40,8 +40,6 @@ import { CompanyRegistryClientService, } from '@island.is/clients/rsk/company-registry' -const WORK_STARTING_HOUR = 8 // 8 AM -const WORK_ENDING_HOUR = 23 // 11 PM type HandleNotification = { profile: { @@ -313,37 +311,12 @@ export class NotificationsWorkerService implements OnApplicationBootstrap { } } - async sleepOutsideWorkingHours(messageId: string): Promise { - const now = new Date() - const currentHour = now.getHours() - const currentMinutes = now.getMinutes() - const currentSeconds = now.getSeconds() - // Is it outside working hours? - if (currentHour >= WORK_ENDING_HOUR || currentHour < WORK_STARTING_HOUR) { - // If it's past the end hour or before the start hour, sleep until the start hour. - const sleepHours = (24 - currentHour + WORK_STARTING_HOUR) % 24 - const sleepDurationMilliSeconds = - (sleepHours * 3600 - currentMinutes * 60 - currentSeconds) * 1000 - this.logger.info( - `Worker will sleep until 8 AM. Sleep duration: ${sleepDurationMilliSeconds} ms`, - { messageId }, - ) - await new Promise((resolve) => - setTimeout(resolve, sleepDurationMilliSeconds), - ) - this.logger.info('Worker waking up after sleep.', { messageId }) - } - } - async run() { await this.worker.run( async (message, job): Promise => { const messageId = job.id this.logger.info('Message received by worker', { messageId }) - // check if we are within operational hours or wait until we are - await this.sleepOutsideWorkingHours(messageId) - const notification = { messageId, ...message } let dbNotification = await this.notificationModel.findOne({ where: { messageId }, diff --git a/libs/message-queue/src/lib/nest/types.ts b/libs/message-queue/src/lib/nest/types.ts index a40f53375c7d..4f5dd81f889e 100644 --- a/libs/message-queue/src/lib/nest/types.ts +++ b/libs/message-queue/src/lib/nest/types.ts @@ -18,6 +18,8 @@ export interface Queue { maxReceiveCount?: number // define a dead-letter queue for messages that fail processing repeatedly deadLetterQueue?: DeadLetterQueue + // if true, the worker will sleep during the night + shouldSleepOutsideWorkingHours?: boolean } export interface DeadLetterQueue { diff --git a/libs/message-queue/src/lib/nest/utils.spec.ts b/libs/message-queue/src/lib/nest/utils.spec.ts index 52d9235032d8..e9d076fbd694 100644 --- a/libs/message-queue/src/lib/nest/utils.spec.ts +++ b/libs/message-queue/src/lib/nest/utils.spec.ts @@ -1,4 +1,4 @@ -import { clamp } from './utils' +import { calculateSleepDurationUntilMorning, clamp, isOutsideWorkingHours, sleepUntilMorning } from './utils' describe('utils', () => { describe('clamp', () => { @@ -12,4 +12,34 @@ describe('utils', () => { expect(clamp(100, min, max)).toBe(10) }) }) + describe('isOutsideWorkingHours', () => { + it('returns true if the current hour is outside working hours', () => { + expect(isOutsideWorkingHours(new Date('2023-01-01T07:00:00'))).toBe(true); // 7 AM + expect(isOutsideWorkingHours(new Date('2023-01-01T23:00:00'))).toBe(true); // 11 PM + expect(isOutsideWorkingHours(new Date('2023-01-01T00:00:00'))).toBe(true); // Midnight + expect(isOutsideWorkingHours(new Date('2023-01-01T08:00:00'))).toBe(false); // 8 AM + expect(isOutsideWorkingHours(new Date('2023-01-01T22:00:00'))).toBe(false); // 10 PM + }); + }); + + describe('calculateSleepDurationUntilMorning', () => { + it('calculates sleep duration correctly for a time at midnight', () => { + const now = new Date('2023-01-01T00:00:00'); // Midnight + const duration = calculateSleepDurationUntilMorning(now); + expect(duration).toBe(28800000); // 8 hours in milliseconds + }); + + it('calculates sleep duration correctly for a time in the middle of the night', () => { + const now = new Date('2023-01-01T05:00:00'); // 11 PM + const duration = calculateSleepDurationUntilMorning(now); + // 3 hour in milliseconds + expect(duration).toBe(10800000); + }); + + it('calculates sleep duration correctly for a time just before work starts', () => { + const now = new Date('2023-01-01T07:59:00'); // 7:59 AM + const duration = calculateSleepDurationUntilMorning(now); + expect(duration).toBe(60000); // 1 minute in milliseconds + }); + }); }) diff --git a/libs/message-queue/src/lib/nest/utils.ts b/libs/message-queue/src/lib/nest/utils.ts index 7cf4bc885a4e..2ffab7816313 100644 --- a/libs/message-queue/src/lib/nest/utils.ts +++ b/libs/message-queue/src/lib/nest/utils.ts @@ -1,4 +1,6 @@ const TOKEN_PREFIX = 'IslandIsMessageQueue' +const WORK_STARTING_HOUR = 8 // 8 AM +const WORK_ENDING_HOUR = 23 // 11 PM export const getQueueServiceToken = (name: string): string => `${TOKEN_PREFIX}/QueueService/${name}` @@ -11,3 +13,23 @@ export const getClientServiceToken = (name: string): string => export const clamp = (v: number, min: number, max: number): number => Math.min(max, Math.max(min, v)) + +export const isOutsideWorkingHours = (now: Date): boolean => { + const currentHour = now.getHours() + + return currentHour < WORK_STARTING_HOUR || currentHour >= WORK_ENDING_HOUR +} + +export const calculateSleepDurationUntilMorning = (now: Date): number => { + const currentHour = now.getHours(); + const currentMinutes = now.getMinutes(); + const currentSeconds = now.getSeconds(); + const sleepHours = (24 - currentHour + WORK_STARTING_HOUR) % 24; + return (sleepHours * 3600 - currentMinutes * 60 - currentSeconds) * 1000; +}; + +export const sleepUntilMorning = (now: Date): Promise => { + const ms = calculateSleepDurationUntilMorning(now) + + return new Promise((resolve) => setTimeout(resolve, ms)) +} diff --git a/libs/message-queue/src/lib/nest/worker.service.ts b/libs/message-queue/src/lib/nest/worker.service.ts index a6afaebacf9b..03f7d9df9315 100644 --- a/libs/message-queue/src/lib/nest/worker.service.ts +++ b/libs/message-queue/src/lib/nest/worker.service.ts @@ -4,7 +4,7 @@ import { Message } from '@aws-sdk/client-sqs' import type { Logger } from '@island.is/logging' import { QueueService } from './queue.service' import type { Queue, Job } from './types' -import { clamp } from './utils' +import { clamp, isOutsideWorkingHours, sleepUntilMorning } from './utils' import { ClientService } from './client.service' type MessageHandler = (handler: T, job: Job) => Promise @@ -20,6 +20,7 @@ enum Status { Running, Stopping, Stopped, + Sleeping, } @Injectable() @@ -46,7 +47,17 @@ export class WorkerService implements OnModuleDestroy { ) this.status = Status.Running + while (this.status === Status.Running) { + + const now = new Date() + if (this.config.shouldSleepOutsideWorkingHours && isOutsideWorkingHours(now)) { + this.logger.info('Outside of working hours - worker sleeping') + this.status = Status.Sleeping + await sleepUntilMorning(now) + this.status = Status.Running + } + const messages = await this.client.receiveMessages(this.queue.url, { maxNumMessages: this.config.maxConcurrentJobs, }) @@ -107,7 +118,7 @@ export class WorkerService implements OnModuleDestroy { } async onModuleDestroy() { - if (this.status === Status.Running) { + if (this.status === Status.Running || this.status === Status.Sleeping) { this.logger.info(`Stopping worker "${this.config.name}"`) if (this.activeJobs !== null) { From 36c98f487729683dd2b758cdf24410af63146124 Mon Sep 17 00:00:00 2001 From: andes-it Date: Mon, 4 Nov 2024 16:03:37 +0000 Subject: [PATCH 02/10] chore: nx format:write update dirty files --- .../notificationsWorker.service.ts | 1 - libs/message-queue/src/lib/nest/utils.spec.ts | 47 ++++++++++--------- libs/message-queue/src/lib/nest/utils.ts | 12 ++--- .../src/lib/nest/worker.service.ts | 6 ++- 4 files changed, 36 insertions(+), 30 deletions(-) diff --git a/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.ts b/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.ts index ff06f31eb6af..e276e1cec7fe 100644 --- a/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.ts +++ b/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.ts @@ -40,7 +40,6 @@ import { CompanyRegistryClientService, } from '@island.is/clients/rsk/company-registry' - type HandleNotification = { profile: { nationalId: string diff --git a/libs/message-queue/src/lib/nest/utils.spec.ts b/libs/message-queue/src/lib/nest/utils.spec.ts index e9d076fbd694..5130b08b5705 100644 --- a/libs/message-queue/src/lib/nest/utils.spec.ts +++ b/libs/message-queue/src/lib/nest/utils.spec.ts @@ -1,4 +1,9 @@ -import { calculateSleepDurationUntilMorning, clamp, isOutsideWorkingHours, sleepUntilMorning } from './utils' +import { + calculateSleepDurationUntilMorning, + clamp, + isOutsideWorkingHours, + sleepUntilMorning, +} from './utils' describe('utils', () => { describe('clamp', () => { @@ -14,32 +19,32 @@ describe('utils', () => { }) describe('isOutsideWorkingHours', () => { it('returns true if the current hour is outside working hours', () => { - expect(isOutsideWorkingHours(new Date('2023-01-01T07:00:00'))).toBe(true); // 7 AM - expect(isOutsideWorkingHours(new Date('2023-01-01T23:00:00'))).toBe(true); // 11 PM - expect(isOutsideWorkingHours(new Date('2023-01-01T00:00:00'))).toBe(true); // Midnight - expect(isOutsideWorkingHours(new Date('2023-01-01T08:00:00'))).toBe(false); // 8 AM - expect(isOutsideWorkingHours(new Date('2023-01-01T22:00:00'))).toBe(false); // 10 PM - }); - }); + expect(isOutsideWorkingHours(new Date('2023-01-01T07:00:00'))).toBe(true) // 7 AM + expect(isOutsideWorkingHours(new Date('2023-01-01T23:00:00'))).toBe(true) // 11 PM + expect(isOutsideWorkingHours(new Date('2023-01-01T00:00:00'))).toBe(true) // Midnight + expect(isOutsideWorkingHours(new Date('2023-01-01T08:00:00'))).toBe(false) // 8 AM + expect(isOutsideWorkingHours(new Date('2023-01-01T22:00:00'))).toBe(false) // 10 PM + }) + }) describe('calculateSleepDurationUntilMorning', () => { it('calculates sleep duration correctly for a time at midnight', () => { - const now = new Date('2023-01-01T00:00:00'); // Midnight - const duration = calculateSleepDurationUntilMorning(now); - expect(duration).toBe(28800000); // 8 hours in milliseconds - }); + const now = new Date('2023-01-01T00:00:00') // Midnight + const duration = calculateSleepDurationUntilMorning(now) + expect(duration).toBe(28800000) // 8 hours in milliseconds + }) it('calculates sleep duration correctly for a time in the middle of the night', () => { - const now = new Date('2023-01-01T05:00:00'); // 11 PM - const duration = calculateSleepDurationUntilMorning(now); + const now = new Date('2023-01-01T05:00:00') // 11 PM + const duration = calculateSleepDurationUntilMorning(now) // 3 hour in milliseconds - expect(duration).toBe(10800000); - }); + expect(duration).toBe(10800000) + }) it('calculates sleep duration correctly for a time just before work starts', () => { - const now = new Date('2023-01-01T07:59:00'); // 7:59 AM - const duration = calculateSleepDurationUntilMorning(now); - expect(duration).toBe(60000); // 1 minute in milliseconds - }); - }); + const now = new Date('2023-01-01T07:59:00') // 7:59 AM + const duration = calculateSleepDurationUntilMorning(now) + expect(duration).toBe(60000) // 1 minute in milliseconds + }) + }) }) diff --git a/libs/message-queue/src/lib/nest/utils.ts b/libs/message-queue/src/lib/nest/utils.ts index 2ffab7816313..1b2668ccf4f8 100644 --- a/libs/message-queue/src/lib/nest/utils.ts +++ b/libs/message-queue/src/lib/nest/utils.ts @@ -21,12 +21,12 @@ export const isOutsideWorkingHours = (now: Date): boolean => { } export const calculateSleepDurationUntilMorning = (now: Date): number => { - const currentHour = now.getHours(); - const currentMinutes = now.getMinutes(); - const currentSeconds = now.getSeconds(); - const sleepHours = (24 - currentHour + WORK_STARTING_HOUR) % 24; - return (sleepHours * 3600 - currentMinutes * 60 - currentSeconds) * 1000; -}; + const currentHour = now.getHours() + const currentMinutes = now.getMinutes() + const currentSeconds = now.getSeconds() + const sleepHours = (24 - currentHour + WORK_STARTING_HOUR) % 24 + return (sleepHours * 3600 - currentMinutes * 60 - currentSeconds) * 1000 +} export const sleepUntilMorning = (now: Date): Promise => { const ms = calculateSleepDurationUntilMorning(now) diff --git a/libs/message-queue/src/lib/nest/worker.service.ts b/libs/message-queue/src/lib/nest/worker.service.ts index 03f7d9df9315..523e0afa5768 100644 --- a/libs/message-queue/src/lib/nest/worker.service.ts +++ b/libs/message-queue/src/lib/nest/worker.service.ts @@ -49,9 +49,11 @@ export class WorkerService implements OnModuleDestroy { this.status = Status.Running while (this.status === Status.Running) { - const now = new Date() - if (this.config.shouldSleepOutsideWorkingHours && isOutsideWorkingHours(now)) { + if ( + this.config.shouldSleepOutsideWorkingHours && + isOutsideWorkingHours(now) + ) { this.logger.info('Outside of working hours - worker sleeping') this.status = Status.Sleeping await sleepUntilMorning(now) From 25c4ae3101c17f7e94fca92facbe6066d200a531 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnea=20R=C3=BAn=20Vignisd=C3=B3ttir?= Date: Tue, 5 Nov 2024 10:42:17 +0000 Subject: [PATCH 03/10] small refactor --- libs/message-queue/src/lib/nest/utils.ts | 24 ++++++++++--------- .../src/lib/nest/worker.service.ts | 22 +++++++++-------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/libs/message-queue/src/lib/nest/utils.ts b/libs/message-queue/src/lib/nest/utils.ts index 1b2668ccf4f8..ad5805cec0d0 100644 --- a/libs/message-queue/src/lib/nest/utils.ts +++ b/libs/message-queue/src/lib/nest/utils.ts @@ -14,22 +14,24 @@ export const getClientServiceToken = (name: string): string => export const clamp = (v: number, min: number, max: number): number => Math.min(max, Math.max(min, v)) -export const isOutsideWorkingHours = (now: Date): boolean => { +export const isOutsideWorkingHours = (): boolean => { + const now = new Date() const currentHour = now.getHours() return currentHour < WORK_STARTING_HOUR || currentHour >= WORK_ENDING_HOUR } -export const calculateSleepDurationUntilMorning = (now: Date): number => { - const currentHour = now.getHours() - const currentMinutes = now.getMinutes() - const currentSeconds = now.getSeconds() - const sleepHours = (24 - currentHour + WORK_STARTING_HOUR) % 24 - return (sleepHours * 3600 - currentMinutes * 60 - currentSeconds) * 1000 -} - -export const sleepUntilMorning = (now: Date): Promise => { - const ms = calculateSleepDurationUntilMorning(now) +export const calculateSleepDurationUntilMorning = (): number => { + const now = new Date(); + const currentHour = now.getHours(); + const currentMinutes = now.getMinutes(); + const currentSeconds = now.getSeconds(); + const sleepHours = (24 - currentHour + WORK_STARTING_HOUR) % 24; + return (sleepHours * 3600 - currentMinutes * 60 - currentSeconds) * 1000; +}; + +export const sleepUntilMorning = (): Promise => { + const ms = calculateSleepDurationUntilMorning() return new Promise((resolve) => setTimeout(resolve, ms)) } diff --git a/libs/message-queue/src/lib/nest/worker.service.ts b/libs/message-queue/src/lib/nest/worker.service.ts index 523e0afa5768..7f727b4632e4 100644 --- a/libs/message-queue/src/lib/nest/worker.service.ts +++ b/libs/message-queue/src/lib/nest/worker.service.ts @@ -49,16 +49,8 @@ export class WorkerService implements OnModuleDestroy { this.status = Status.Running while (this.status === Status.Running) { - const now = new Date() - if ( - this.config.shouldSleepOutsideWorkingHours && - isOutsideWorkingHours(now) - ) { - this.logger.info('Outside of working hours - worker sleeping') - this.status = Status.Sleeping - await sleepUntilMorning(now) - this.status = Status.Running - } + + await this.maybeSleepOutsideWorkingHours() const messages = await this.client.receiveMessages(this.queue.url, { maxNumMessages: this.config.maxConcurrentJobs, @@ -70,6 +62,16 @@ export class WorkerService implements OnModuleDestroy { } } + private async maybeSleepOutsideWorkingHours() { + if (this.config.shouldSleepOutsideWorkingHours && isOutsideWorkingHours()) { + this.logger.info('Outside of working hours - worker sleeping') + this.status = Status.Sleeping + await sleepUntilMorning() + this.logger.info('Worker waking up') + this.status = Status.Running + } + } + private getConcurrency(): number { const concurrency = this.config.maxConcurrentJobs ?? DEFAULT_BATCH_SIZE From f5cb615313f0f63050f3fa1fd5b9002b085e5301 Mon Sep 17 00:00:00 2001 From: andes-it Date: Tue, 5 Nov 2024 11:02:10 +0000 Subject: [PATCH 04/10] chore: nx format:write update dirty files --- libs/message-queue/src/lib/nest/utils.ts | 14 +++++++------- libs/message-queue/src/lib/nest/worker.service.ts | 3 +-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/libs/message-queue/src/lib/nest/utils.ts b/libs/message-queue/src/lib/nest/utils.ts index ad5805cec0d0..4ad97db3c7e2 100644 --- a/libs/message-queue/src/lib/nest/utils.ts +++ b/libs/message-queue/src/lib/nest/utils.ts @@ -22,13 +22,13 @@ export const isOutsideWorkingHours = (): boolean => { } export const calculateSleepDurationUntilMorning = (): number => { - const now = new Date(); - const currentHour = now.getHours(); - const currentMinutes = now.getMinutes(); - const currentSeconds = now.getSeconds(); - const sleepHours = (24 - currentHour + WORK_STARTING_HOUR) % 24; - return (sleepHours * 3600 - currentMinutes * 60 - currentSeconds) * 1000; -}; + const now = new Date() + const currentHour = now.getHours() + const currentMinutes = now.getMinutes() + const currentSeconds = now.getSeconds() + const sleepHours = (24 - currentHour + WORK_STARTING_HOUR) % 24 + return (sleepHours * 3600 - currentMinutes * 60 - currentSeconds) * 1000 +} export const sleepUntilMorning = (): Promise => { const ms = calculateSleepDurationUntilMorning() diff --git a/libs/message-queue/src/lib/nest/worker.service.ts b/libs/message-queue/src/lib/nest/worker.service.ts index 7f727b4632e4..da4445603cea 100644 --- a/libs/message-queue/src/lib/nest/worker.service.ts +++ b/libs/message-queue/src/lib/nest/worker.service.ts @@ -49,8 +49,7 @@ export class WorkerService implements OnModuleDestroy { this.status = Status.Running while (this.status === Status.Running) { - - await this.maybeSleepOutsideWorkingHours() + await this.maybeSleepOutsideWorkingHours() const messages = await this.client.receiveMessages(this.queue.url, { maxNumMessages: this.config.maxConcurrentJobs, From 3cc34d75bd44e29c273a3a8d6a368f6cde21e18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnea=20R=C3=BAn=20Vignisd=C3=B3ttir?= Date: Thu, 7 Nov 2024 16:21:36 +0000 Subject: [PATCH 05/10] Update libs/message-queue/src/lib/nest/utils.spec.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- libs/message-queue/src/lib/nest/utils.spec.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/libs/message-queue/src/lib/nest/utils.spec.ts b/libs/message-queue/src/lib/nest/utils.spec.ts index 5130b08b5705..955f2f216f32 100644 --- a/libs/message-queue/src/lib/nest/utils.spec.ts +++ b/libs/message-queue/src/lib/nest/utils.spec.ts @@ -28,23 +28,31 @@ describe('utils', () => { }) describe('calculateSleepDurationUntilMorning', () => { + const HOUR_IN_MS = 3600000; + const MINUTE_IN_MS = 60000; + it('calculates sleep duration correctly for a time at midnight', () => { const now = new Date('2023-01-01T00:00:00') // Midnight const duration = calculateSleepDurationUntilMorning(now) - expect(duration).toBe(28800000) // 8 hours in milliseconds + expect(duration).toBe(8 * HOUR_IN_MS) // 8 hours until 8:00 AM }) it('calculates sleep duration correctly for a time in the middle of the night', () => { - const now = new Date('2023-01-01T05:00:00') // 11 PM + const now = new Date('2023-01-01T05:00:00') // 5:00 AM const duration = calculateSleepDurationUntilMorning(now) - // 3 hour in milliseconds - expect(duration).toBe(10800000) + expect(duration).toBe(3 * HOUR_IN_MS) // 3 hours until 8:00 AM }) it('calculates sleep duration correctly for a time just before work starts', () => { const now = new Date('2023-01-01T07:59:00') // 7:59 AM const duration = calculateSleepDurationUntilMorning(now) - expect(duration).toBe(60000) // 1 minute in milliseconds + expect(duration).toBe(MINUTE_IN_MS) // 1 minute until 8:00 AM + }) + + it('returns appropriate duration when called during working hours', () => { + const now = new Date('2023-01-01T14:00:00') // 2:00 PM + const duration = calculateSleepDurationUntilMorning(now) + expect(duration).toBe(18 * HOUR_IN_MS) // 18 hours until next morning 8:00 AM }) }) }) From f9eb6d2223d569e4a194fed9b16f0e6b6ad2329a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnea=20R=C3=BAn=20Vignisd=C3=B3ttir?= Date: Thu, 7 Nov 2024 16:56:16 +0000 Subject: [PATCH 06/10] fix message-queue tests --- .../notificationsWorker.service.spec.ts | 2 +- libs/message-queue/src/lib/nest/utils.spec.ts | 45 ++++++------------- 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts b/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts index ad6163f1d511..051cbc948f69 100644 --- a/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts +++ b/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts @@ -236,7 +236,7 @@ describe('NotificationsWorkerService', () => { expect(notificationDispatch.sendPushNotification).toHaveBeenCalledWith( expect.objectContaining({ nationalId: userWithDelegations.nationalId, - notificationId: recipientMessage.id, + notificationId: recipientMessage?.id, }), ) diff --git a/libs/message-queue/src/lib/nest/utils.spec.ts b/libs/message-queue/src/lib/nest/utils.spec.ts index 955f2f216f32..41927ec07ffc 100644 --- a/libs/message-queue/src/lib/nest/utils.spec.ts +++ b/libs/message-queue/src/lib/nest/utils.spec.ts @@ -2,9 +2,13 @@ import { calculateSleepDurationUntilMorning, clamp, isOutsideWorkingHours, - sleepUntilMorning, } from './utils' +const insideWorkingHours = new Date(2021, 1, 1, 9, 0, 0) +const outsideWorkingHours = new Date(2021, 1, 1, 7, 0, 0) +const HOUR_IN_MS = 3600000; + + describe('utils', () => { describe('clamp', () => { it('clamps value between min and max', () => { @@ -19,40 +23,19 @@ describe('utils', () => { }) describe('isOutsideWorkingHours', () => { it('returns true if the current hour is outside working hours', () => { - expect(isOutsideWorkingHours(new Date('2023-01-01T07:00:00'))).toBe(true) // 7 AM - expect(isOutsideWorkingHours(new Date('2023-01-01T23:00:00'))).toBe(true) // 11 PM - expect(isOutsideWorkingHours(new Date('2023-01-01T00:00:00'))).toBe(true) // Midnight - expect(isOutsideWorkingHours(new Date('2023-01-01T08:00:00'))).toBe(false) // 8 AM - expect(isOutsideWorkingHours(new Date('2023-01-01T22:00:00'))).toBe(false) // 10 PM + jest.useFakeTimers({ now: outsideWorkingHours }) + expect(isOutsideWorkingHours()).toBe(true) + }) + it('returns false if the current hour is inside working hours', () => { + jest.useFakeTimers({ now: insideWorkingHours }) + expect(isOutsideWorkingHours()).toBe(false) }) }) describe('calculateSleepDurationUntilMorning', () => { - const HOUR_IN_MS = 3600000; - const MINUTE_IN_MS = 60000; - - it('calculates sleep duration correctly for a time at midnight', () => { - const now = new Date('2023-01-01T00:00:00') // Midnight - const duration = calculateSleepDurationUntilMorning(now) - expect(duration).toBe(8 * HOUR_IN_MS) // 8 hours until 8:00 AM - }) - - it('calculates sleep duration correctly for a time in the middle of the night', () => { - const now = new Date('2023-01-01T05:00:00') // 5:00 AM - const duration = calculateSleepDurationUntilMorning(now) - expect(duration).toBe(3 * HOUR_IN_MS) // 3 hours until 8:00 AM - }) - - it('calculates sleep duration correctly for a time just before work starts', () => { - const now = new Date('2023-01-01T07:59:00') // 7:59 AM - const duration = calculateSleepDurationUntilMorning(now) - expect(duration).toBe(MINUTE_IN_MS) // 1 minute until 8:00 AM - }) - - it('returns appropriate duration when called during working hours', () => { - const now = new Date('2023-01-01T14:00:00') // 2:00 PM - const duration = calculateSleepDurationUntilMorning(now) - expect(duration).toBe(18 * HOUR_IN_MS) // 18 hours until next morning 8:00 AM + it('calculates the time until the next morning', () => { + jest.useFakeTimers({ now: new Date(2021, 1, 1, 23, 0, 0) }) // 11 PM + expect(calculateSleepDurationUntilMorning()).toBe(9 * HOUR_IN_MS) // 9 hours }) }) }) From c6978a30e424d486120e74d208ee7ad0a93785c4 Mon Sep 17 00:00:00 2001 From: andes-it Date: Thu, 7 Nov 2024 17:08:18 +0000 Subject: [PATCH 07/10] chore: nx format:write update dirty files --- libs/message-queue/src/lib/nest/utils.spec.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/message-queue/src/lib/nest/utils.spec.ts b/libs/message-queue/src/lib/nest/utils.spec.ts index 41927ec07ffc..6758791a21b7 100644 --- a/libs/message-queue/src/lib/nest/utils.spec.ts +++ b/libs/message-queue/src/lib/nest/utils.spec.ts @@ -6,8 +6,7 @@ import { const insideWorkingHours = new Date(2021, 1, 1, 9, 0, 0) const outsideWorkingHours = new Date(2021, 1, 1, 7, 0, 0) -const HOUR_IN_MS = 3600000; - +const HOUR_IN_MS = 3600000 describe('utils', () => { describe('clamp', () => { From 16091aed4e27a52189111ee17cd978b4deee6dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnea=20R=C3=BAn=20Vignisd=C3=B3ttir?= Date: Fri, 8 Nov 2024 11:05:43 +0000 Subject: [PATCH 08/10] move sleep check --- libs/message-queue/src/lib/nest/worker.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/message-queue/src/lib/nest/worker.service.ts b/libs/message-queue/src/lib/nest/worker.service.ts index da4445603cea..1bab21e78cac 100644 --- a/libs/message-queue/src/lib/nest/worker.service.ts +++ b/libs/message-queue/src/lib/nest/worker.service.ts @@ -49,12 +49,12 @@ export class WorkerService implements OnModuleDestroy { this.status = Status.Running while (this.status === Status.Running) { - await this.maybeSleepOutsideWorkingHours() - const messages = await this.client.receiveMessages(this.queue.url, { maxNumMessages: this.config.maxConcurrentJobs, }) + await this.maybeSleepOutsideWorkingHours() + this.activeJobs = this.handleMessageBatch(messages, messageHandler) await this.activeJobs this.activeJobs = null From c4c65b005f5f01eb28ef8a8e2d13dd6b706953e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnea=20R=C3=BAn=20Vignisd=C3=B3ttir?= Date: Mon, 11 Nov 2024 13:48:46 +0000 Subject: [PATCH 09/10] change placement of sleep check back --- .../notificationsWorker.service.spec.ts | 13 ++++++++----- libs/message-queue/src/lib/nest/worker.service.ts | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts b/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts index 051cbc948f69..638415eec4f6 100644 --- a/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts +++ b/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts @@ -368,21 +368,24 @@ describe('NotificationsWorkerService', () => { }) it('should not send email or push notification if we are outside working hours (8 AM - 11 PM) ', async () => { - // set time to be outside of working hours + jest.setSystemTime(outsideWorkingHours) + // First message will be handled since the receiveMessages call is waiting (wait time is max 20s and returns when a message is ready) + // This ensures that the next message is added after time is set outside working hours + await addToQueue(userWithNoDelegations.nationalId) await addToQueue(userWithNoDelegations.nationalId) - expect(emailService.sendEmail).not.toHaveBeenCalled() - expect(notificationDispatch.sendPushNotification).not.toHaveBeenCalled() + expect(emailService.sendEmail).toHaveBeenCalledTimes(1) + expect(notificationDispatch.sendPushNotification).toHaveBeenCalledTimes(1) // reset time to inside working hour jest.advanceTimersByTime(workingHoursDelta) // give worker some time to process message await wait(2) - expect(emailService.sendEmail).toHaveBeenCalledTimes(1) - expect(notificationDispatch.sendPushNotification).toHaveBeenCalledTimes(1) + expect(emailService.sendEmail).toHaveBeenCalledTimes(2) + expect(notificationDispatch.sendPushNotification).toHaveBeenCalledTimes(2) }, 10_000) it('should not send email or push notification if no profile is found for recipient', async () => { diff --git a/libs/message-queue/src/lib/nest/worker.service.ts b/libs/message-queue/src/lib/nest/worker.service.ts index 1bab21e78cac..da4445603cea 100644 --- a/libs/message-queue/src/lib/nest/worker.service.ts +++ b/libs/message-queue/src/lib/nest/worker.service.ts @@ -49,12 +49,12 @@ export class WorkerService implements OnModuleDestroy { this.status = Status.Running while (this.status === Status.Running) { + await this.maybeSleepOutsideWorkingHours() + const messages = await this.client.receiveMessages(this.queue.url, { maxNumMessages: this.config.maxConcurrentJobs, }) - await this.maybeSleepOutsideWorkingHours() - this.activeJobs = this.handleMessageBatch(messages, messageHandler) await this.activeJobs this.activeJobs = null From 9bf794294f813376a86791cfd920483e88101e42 Mon Sep 17 00:00:00 2001 From: andes-it Date: Mon, 11 Nov 2024 14:00:59 +0000 Subject: [PATCH 10/10] chore: nx format:write update dirty files --- .../notificationsWorker/notificationsWorker.service.spec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts b/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts index 638415eec4f6..ce392468eb87 100644 --- a/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts +++ b/apps/services/user-notification/src/app/modules/notifications/notificationsWorker/notificationsWorker.service.spec.ts @@ -368,7 +368,6 @@ describe('NotificationsWorkerService', () => { }) it('should not send email or push notification if we are outside working hours (8 AM - 11 PM) ', async () => { - jest.setSystemTime(outsideWorkingHours) // First message will be handled since the receiveMessages call is waiting (wait time is max 20s and returns when a message is ready)