From f44264be2c1c6c0d847d8b3912baedcc2df6f916 Mon Sep 17 00:00:00 2001 From: tholulomo Date: Tue, 20 Aug 2024 11:44:41 -0400 Subject: [PATCH] FEAT(#508): Using time server for cron jobs --- resfulservice/spec/mocks/taskMock.js | 19 ++- .../spec/sw/utils/worker-service.spec.js | 7 ++ resfulservice/src/sw/index.js | 5 +- resfulservice/src/sw/utils/worker-services.js | 108 +++++++++++++++--- 4 files changed, 121 insertions(+), 18 deletions(-) diff --git a/resfulservice/spec/mocks/taskMock.js b/resfulservice/spec/mocks/taskMock.js index d526bd63..e8679a76 100644 --- a/resfulservice/spec/mocks/taskMock.js +++ b/resfulservice/spec/mocks/taskMock.js @@ -240,6 +240,22 @@ const fetchedCuration = { } }; +const mockTimeApiResponse = { + year: 2024, + month: 6, + day: 6, + hour: 6, + minute: 44, + seconds: 38, + milliSeconds: 875, + dateTime: '2024-06-06T06:44:38.8753094', + date: '06/06/2024', + time: '06:44', + timeZone: 'US/Eastern', + dayOfWeek: 'Thursday', + dstActive: true +}; + module.exports = { mockTasks, mockNonExistingService, @@ -251,5 +267,6 @@ module.exports = { searchedKnowledgeGraph, mockElasticSearchChartsResult, mockFavoriteChart, - fetchedCuration + fetchedCuration, + mockTimeApiResponse }; diff --git a/resfulservice/spec/sw/utils/worker-service.spec.js b/resfulservice/spec/sw/utils/worker-service.spec.js index 0cbc8c2b..750689ce 100644 --- a/resfulservice/spec/sw/utils/worker-service.spec.js +++ b/resfulservice/spec/sw/utils/worker-service.spec.js @@ -1,3 +1,4 @@ +const axios = require('axios'); const { expect } = require('chai'); const fs = require('fs'); const sinon = require('sinon'); @@ -21,6 +22,12 @@ const CuratedSamples = require('../../../src/models/curatedSamples'); const minioClient = require('../../../src/utils/minio'); describe('Worker Services', function () { + beforeEach(() => { + axiosStub = sinon + .stub(axios, 'get') + .resolves({ data: { dateTime: new Date().toISOString() } }); + clock = sinon.useFakeTimers(); + }); afterEach(() => sinon.restore()); context('workerManager', () => { diff --git a/resfulservice/src/sw/index.js b/resfulservice/src/sw/index.js index af441f0d..d0f16959 100644 --- a/resfulservice/src/sw/index.js +++ b/resfulservice/src/sw/index.js @@ -3,10 +3,11 @@ const mongoose = require('mongoose'); const { log } = require('../middlewares'); const WorkerService = require('./utils/worker-services'); const Debouncer = require('./utils/debouncer'); +const { ServiceWorkerDebouncerTimer } = require('../../config/constant'); const env = process.env; -const catchAllHandler = (request, response) => { +const catchAllHandler = (_request, response) => { response.writeHead(200, { 'Content-Type': 'application/json' }); @@ -34,7 +35,7 @@ mongoose }); const debouncedWorkerManager = Debouncer.debounce( WorkerService.workerManager, - 120000 + ServiceWorkerDebouncerTimer ); debouncedWorkerManager(log); }) diff --git a/resfulservice/src/sw/utils/worker-services.js b/resfulservice/src/sw/utils/worker-services.js index da018e43..4eaad47b 100644 --- a/resfulservice/src/sw/utils/worker-services.js +++ b/resfulservice/src/sw/utils/worker-services.js @@ -1,10 +1,12 @@ const sharp = require('sharp'); const fs = require('fs'); +const axios = require('axios'); const CuratedSamples = require('../../models/curatedSamples'); const Task = require('../models/task'); const FileManager = require('../../utils/fileManager'); const KnowledgeController = require('../../controllers/kgWrapperController'); const minioClient = require('../../utils/minio'); +const { log } = require('../../middlewares'); const { SupportedFileResponseHeaders, MinioBucket, @@ -14,6 +16,90 @@ const { stringifyError } = require('../../utils/exit-utils'); const env = process.env; const BUCKETNAME = env.MINIO_BUCKET ?? MinioBucket; +const TIME_API_URL = + 'https://timeapi.io/api/Time/current/zone?timeZone=US/Eastern'; + +// Global variables to store the fetched time and date +let fetchedTime = null; +let fetchedDate = null; + +// Function to fetch the current time from the API +async function fetchCurrentTime() { + log.info('fetchCurrentTime(): Function entry'); + try { + const response = await axios.get(TIME_API_URL); + if (response.status === 200) { + const data = response.data; + log.info(`Fetched time: ${data.dateTime}`); + fetchedTime = new Date(data.dateTime); + fetchedDate = fetchedTime.toISOString().split('T')[0]; + } else { + log.error('Failed to fetch time from the API'); + throw new Error('Failed to fetch time from the API'); + } + } catch (error) { + log.error(error); + } +} + +// Function to calculate the remaining time until 12:00 AM in the correct timezone +function getRemainingTimeUntilMidnight() { + log.info('getRemainingTimeUntilMidnight(): Function entry'); + const now = new Date(); + const timezoneOffset = now.getTimezoneOffset() * 60000; + const nowInEST = new Date(now.getTime() - timezoneOffset + 3600000 * -5); // EST is UTC-5 + const nextMidnight = new Date(nowInEST); + nextMidnight.setHours(0, 0, 0, 0); + + // If it's already past 12:00 AM today, set nextMidnight to 12:00 AM the next day + if (nowInEST >= nextMidnight) { + nextMidnight.setDate(nextMidnight.getDate() + 1); + } + + return nextMidnight - nowInEST; +} + +// Function to check if the current time is between 12:00 AM and 3:00 AM +function isNightTime() { + log.info('isNightTime(): Function entry'); + if (fetchedTime !== null) { + const startTime = new Date(fetchedTime); + startTime.setHours(0, 0, 0, 0); + const endTime = new Date(fetchedTime); + endTime.setHours(3, 0, 0, 0); + return fetchedTime >= startTime && fetchedTime < endTime; + } else { + return false; + } +} + +// Function to update fetched time and date periodically +async function updateTimeIfNecessary() { + log.info('updateTimeIfNecessary(): Function entry'); + const now = new Date(); + const timezoneOffset = now.getTimezoneOffset() * 60000; + const nowInEST = new Date(now.getTime() - timezoneOffset + 3600000 * -5); // EST is UTC-5 + const currentDate = nowInEST.toISOString().split('T')[0]; + + // Check if it's a new day + if (fetchedDate !== currentDate) { + await fetchCurrentTime(); + } else { + // Increment fetchedTime by 3 minutes + fetchedTime = new Date(fetchedTime.getTime() + 3 * 60 * 1000); + } +} + +// Initial fetch of the current time +fetchCurrentTime().then(() => { + // Set a timer to fetch the time from the API at 12:00 AM + const remainingTimeUntilMidnight = getRemainingTimeUntilMidnight(); + setTimeout(async () => { + await fetchCurrentTime(); + console.log('Fetched time at 12:00 AM:', fetchedTime); + }, remainingTimeUntilMidnight); +}); + const serviceManager = { convertImageToPng: { serviceName: 'convertImageToPng', @@ -27,13 +113,16 @@ const serviceManager = { } }; -async function workerManager (logger) { +async function workerManager(logger) { const tasks = await Task.find({ status: { $nin: [TaskStatusMap.MISSING, TaskStatusMap.DISABLED] } }); if (!tasks.length) return; + await updateTimeIfNecessary(); + logger.info('current time: ', fetchedTime); + tasks.forEach(async (task) => { const service = serviceManager[task.serviceName]; if (!service) { @@ -73,7 +162,7 @@ async function workerManager (logger) { }); } -async function convertImageToPng ({ _id, info: { ref, sampleID } }, logger) { +async function convertImageToPng({ _id, info: { ref, sampleID } }, logger) { logger.info('Worker-services.convertImageToPng - Function entry'); const pngFilePath = `${ref.split(/.tiff?/)[0]}.png`; const pngFile = pngFilePath.split('mm_files/')[1]; @@ -215,7 +304,7 @@ async function convertImageToPng ({ _id, info: { ref, sampleID } }, logger) { } } -async function knowledgeRequest ( +async function knowledgeRequest( { _id: uuid, info: { knowledgeId, req } }, logger ) { @@ -268,7 +357,7 @@ const isObjectExistInMinio = async (bucketName, fileName) => { } }; -async function checkFileExistence (filePath) { +async function checkFileExistence(filePath) { try { await fs.promises.access(filePath, fs.constants.F_OK); return true; @@ -297,15 +386,4 @@ const generateTempFileName = (filepath) => { return `mm_files/failed_upload_${filename}`; }; -const isNightTime = () => { - const options = { - timeZone: 'America/New_York', // Specify the timezone - hour12: false, // Set to true for 12-hour format, false for 24-hour format - hour: '2-digit' // Set to '2-digit' to get the hour - }; - - const currentHour = new Date().toLocaleString('en-US', options); - return currentHour >= 0 && currentHour <= 3; -}; - module.exports = { convertImageToPng, workerManager, knowledgeRequest };