From 18f5dc71038a89c6f8e42d68bffc8bb5c67ca7fe Mon Sep 17 00:00:00 2001 From: Dan Gowans Date: Mon, 27 Mar 2023 11:03:43 -0400 Subject: [PATCH] clear lot cache messaging --- bin/www.js | 12 ++--- bin/www.ts | 14 +++--- helpers/functions.cache.ts | 6 +-- helpers/functions.lots.d.ts | 2 +- helpers/functions.lots.js | 52 +++++++++++++++++-- helpers/functions.lots.ts | 78 +++++++++++++++++++++++++++-- helpers/lotOccupancyDB/updateLot.js | 4 ++ helpers/lotOccupancyDB/updateLot.ts | 7 +++ package.json | 4 +- types/applicationTypes.d.ts | 16 +++++- types/applicationTypes.ts | 20 +++++++- 11 files changed, 184 insertions(+), 31 deletions(-) diff --git a/bin/www.js b/bin/www.js index 641ec8bc..5ddaba3b 100644 --- a/bin/www.js +++ b/bin/www.js @@ -25,14 +25,12 @@ for (let index = 0; index < processCount; index += 1) { activeWorkers.set(worker.process.pid, worker); } cluster.on('message', (worker, message) => { - if (message?.messageType === 'clearCache') { - for (const [pid, worker] of activeWorkers.entries()) { - if (worker === undefined || pid === message.pid) { - continue; - } - debug('Relaying message to workers'); - worker.send(message); + for (const [pid, worker] of activeWorkers.entries()) { + if (worker === undefined || pid === message.pid) { + continue; } + debug('Relaying message to workers'); + worker.send(message); } }); cluster.on('exit', (worker, code, signal) => { diff --git a/bin/www.ts b/bin/www.ts index c62352fa..e7d9d6af 100644 --- a/bin/www.ts +++ b/bin/www.ts @@ -45,15 +45,13 @@ for (let index = 0; index < processCount; index += 1) { } cluster.on('message', (worker, message: WorkerMessage) => { - if (message?.messageType === 'clearCache') { - for (const [pid, worker] of activeWorkers.entries()) { - if (worker === undefined || pid === message.pid) { - continue - } - - debug('Relaying message to workers') - worker.send(message) + for (const [pid, worker] of activeWorkers.entries()) { + if (worker === undefined || pid === message.pid) { + continue } + + debug('Relaying message to workers') + worker.send(message) } }) diff --git a/helpers/functions.cache.ts b/helpers/functions.cache.ts index 18e3256e..c1d40722 100644 --- a/helpers/functions.cache.ts +++ b/helpers/functions.cache.ts @@ -18,7 +18,7 @@ import { getWorkOrderTypes as getWorkOrderTypesFromDatabase } from './lotOccupan import { getWorkOrderMilestoneTypes as getWorkOrderMilestoneTypesFromDatabase } from './lotOccupancyDB/getWorkOrderMilestoneTypes.js' import type * as recordTypes from '../types/recordTypes' -import type { WorkerMessage } from '../types/applicationTypes' +import type { ClearCacheWorkerMessage } from '../types/applicationTypes' import Debug from 'debug' const debug = Debug(`lot-occupancy-system:functions.cache:${process.pid}`) @@ -343,7 +343,7 @@ export function clearCacheByTableName( try { if (relayMessage && cluster.isWorker) { - const workerMessage: WorkerMessage = { + const workerMessage: ClearCacheWorkerMessage = { messageType: 'clearCache', tableName, timeMillis: Date.now(), @@ -357,7 +357,7 @@ export function clearCacheByTableName( } catch {} } -process.on('message', (message: WorkerMessage) => { +process.on('message', (message: ClearCacheWorkerMessage) => { if (message.messageType === 'clearCache' && message.pid !== process.pid) { debug(`Clearing cache: ${message.tableName}`) clearCacheByTableName(message.tableName, false) diff --git a/helpers/functions.lots.d.ts b/helpers/functions.lots.d.ts index 69f0b584..e43ad87b 100644 --- a/helpers/functions.lots.d.ts +++ b/helpers/functions.lots.d.ts @@ -1,3 +1,3 @@ export declare function getNextLotId(lotId: number): Promise; export declare function getPreviousLotId(lotId: number): Promise; -export declare function clearNextPreviousLotIdCache(lotId?: number): void; +export declare function clearNextPreviousLotIdCache(lotId: number | -1, relayMessage?: boolean): void; diff --git a/helpers/functions.lots.js b/helpers/functions.lots.js index c8820552..061e7681 100644 --- a/helpers/functions.lots.js +++ b/helpers/functions.lots.js @@ -1,15 +1,32 @@ +import cluster from 'node:cluster'; import NodeCache from 'node-cache'; import getPreviousLotIdFromDatabase from './lotOccupancyDB/getPreviousLotId.js'; import getNextLotIdFromDatabase from './lotOccupancyDB/getNextLotId.js'; +import Debug from 'debug'; +const debug = Debug(`lot-occupancy-system:functions.lots:${process.pid}`); const cacheOptions = { stdTTL: 2 * 60, useClones: false }; const previousLotIdCache = new NodeCache(cacheOptions); const nextLotIdCache = new NodeCache(cacheOptions); -function cacheLotIds(lotId, nextLotId) { +function cacheLotIds(lotId, nextLotId, relayMessage = true) { previousLotIdCache.set(nextLotId, lotId); nextLotIdCache.set(lotId, nextLotId); + try { + if (relayMessage && cluster.isWorker) { + const workerMessage = { + messageType: 'cacheLotIds', + lotId, + nextLotId, + timeMillis: Date.now(), + pid: process.pid + }; + debug(`Sending cache lot ids from worker: (${lotId}, ${nextLotId})`); + process.send(workerMessage); + } + } + catch { } } export async function getNextLotId(lotId) { let nextLotId = nextLotIdCache.get(lotId); @@ -31,8 +48,8 @@ export async function getPreviousLotId(lotId) { } return previousLotId; } -export function clearNextPreviousLotIdCache(lotId) { - if (lotId === undefined) { +export function clearNextPreviousLotIdCache(lotId, relayMessage = true) { + if (lotId === undefined || lotId === -1) { previousLotIdCache.flushAll(); nextLotIdCache.flushAll(); return; @@ -47,4 +64,33 @@ export function clearNextPreviousLotIdCache(lotId) { previousLotIdCache.del(nextLotId); nextLotIdCache.del(lotId); } + try { + if (relayMessage && cluster.isWorker) { + const workerMessage = { + messageType: 'clearNextPreviousLotIdCache', + lotId, + timeMillis: Date.now(), + pid: process.pid + }; + debug(`Sending clear next/previous lot cache from worker: ${lotId}`); + process.send(workerMessage); + } + } + catch { } } +process.on('message', (message) => { + if (message.pid !== process.pid) { + switch (message.messageType) { + case 'cacheLotIds': { + debug(`Caching lot ids: (${message.lotId}, ${message.nextLotId})`); + cacheLotIds(message.lotId, message.nextLotId, false); + break; + } + case 'clearNextPreviousLotIdCache': { + debug(`Clearing next/previous lot cache: ${message.lotId}`); + clearNextPreviousLotIdCache(message.lotId, false); + break; + } + } + } +}); diff --git a/helpers/functions.lots.ts b/helpers/functions.lots.ts index 5a0d2fa8..9ab4d972 100644 --- a/helpers/functions.lots.ts +++ b/helpers/functions.lots.ts @@ -1,8 +1,18 @@ +import cluster from 'node:cluster' + import NodeCache from 'node-cache' import getPreviousLotIdFromDatabase from './lotOccupancyDB/getPreviousLotId.js' import getNextLotIdFromDatabase from './lotOccupancyDB/getNextLotId.js' +import type { + CacheLotIdsWorkerMessage, + ClearNextPreviousLotIdsCacheWorkerMessage +} from '../types/applicationTypes.js' + +import Debug from 'debug' +const debug = Debug(`lot-occupancy-system:functions.lots:${process.pid}`) + const cacheOptions: NodeCache.Options = { stdTTL: 2 * 60, // two minutes useClones: false @@ -12,9 +22,29 @@ const previousLotIdCache = new NodeCache(cacheOptions) const nextLotIdCache = new NodeCache(cacheOptions) -function cacheLotIds(lotId: number, nextLotId: number): void { +function cacheLotIds( + lotId: number, + nextLotId: number, + relayMessage = true +): void { previousLotIdCache.set(nextLotId, lotId) nextLotIdCache.set(lotId, nextLotId) + + try { + if (relayMessage && cluster.isWorker) { + const workerMessage: CacheLotIdsWorkerMessage = { + messageType: 'cacheLotIds', + lotId, + nextLotId, + timeMillis: Date.now(), + pid: process.pid + } + + debug(`Sending cache lot ids from worker: (${lotId}, ${nextLotId})`) + + process.send!(workerMessage) + } + } catch {} } export async function getNextLotId(lotId: number): Promise { @@ -47,8 +77,11 @@ export async function getPreviousLotId( return previousLotId } -export function clearNextPreviousLotIdCache(lotId?: number): void { - if (lotId === undefined) { +export function clearNextPreviousLotIdCache( + lotId: number | -1, + relayMessage = true +): void { + if (lotId === undefined || lotId === -1) { previousLotIdCache.flushAll() nextLotIdCache.flushAll() return @@ -67,4 +100,43 @@ export function clearNextPreviousLotIdCache(lotId?: number): void { previousLotIdCache.del(nextLotId) nextLotIdCache.del(lotId) } + + try { + if (relayMessage && cluster.isWorker) { + const workerMessage: ClearNextPreviousLotIdsCacheWorkerMessage = { + messageType: 'clearNextPreviousLotIdCache', + lotId, + timeMillis: Date.now(), + pid: process.pid + } + + debug(`Sending clear next/previous lot cache from worker: ${lotId}`) + + process.send!(workerMessage) + } + } catch {} } + +process.on( + 'message', + ( + message: + | ClearNextPreviousLotIdsCacheWorkerMessage + | CacheLotIdsWorkerMessage + ) => { + if (message.pid !== process.pid) { + switch (message.messageType) { + case 'cacheLotIds': { + debug(`Caching lot ids: (${message.lotId}, ${message.nextLotId})`) + cacheLotIds(message.lotId, message.nextLotId, false) + break + } + case 'clearNextPreviousLotIdCache': { + debug(`Clearing next/previous lot cache: ${message.lotId}`) + clearNextPreviousLotIdCache(message.lotId, false) + break + } + } + } + } +) diff --git a/helpers/lotOccupancyDB/updateLot.js b/helpers/lotOccupancyDB/updateLot.js index b73497cd..c6998c95 100644 --- a/helpers/lotOccupancyDB/updateLot.js +++ b/helpers/lotOccupancyDB/updateLot.js @@ -1,6 +1,7 @@ import { acquireConnection } from './pool.js'; import { addOrUpdateLotField } from './addOrUpdateLotField.js'; import { deleteLotField } from './deleteLotField.js'; +import { clearNextPreviousLotIdCache } from '../functions.lots.js'; export async function updateLot(lotForm, requestSession) { const database = await acquireConnection(); const rightNowMillis = Date.now(); @@ -32,6 +33,9 @@ export async function updateLot(lotForm, requestSession) { } } database.release(); + clearNextPreviousLotIdCache(typeof lotForm.lotId === 'number' + ? lotForm.lotId + : Number.parseInt(lotForm.lotId, 10)); return result.changes > 0; } export async function updateLotStatus(lotId, lotStatusId, requestSession) { diff --git a/helpers/lotOccupancyDB/updateLot.ts b/helpers/lotOccupancyDB/updateLot.ts index 15daa98a..ce9b2354 100644 --- a/helpers/lotOccupancyDB/updateLot.ts +++ b/helpers/lotOccupancyDB/updateLot.ts @@ -5,6 +5,7 @@ import { addOrUpdateLotField } from './addOrUpdateLotField.js' import { deleteLotField } from './deleteLotField.js' import type * as recordTypes from '../../types/recordTypes' +import { clearNextPreviousLotIdCache } from '../functions.lots.js' interface UpdateLotForm { lotId: string | number @@ -87,6 +88,12 @@ export async function updateLot( database.release() + clearNextPreviousLotIdCache( + typeof lotForm.lotId === 'number' + ? lotForm.lotId + : Number.parseInt(lotForm.lotId, 10) + ) + return result.changes > 0 } diff --git a/package.json b/package.json index 0fb8f8ec..64cef49e 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "scripts": { "start": "cross-env NODE_ENV=production node ./bin/www.js", "dev:test": "cross-env NODE_ENV=dev DEBUG=lot-occupancy-system:*,dynamics-gp:* TEST_DATABASES=true nodemon --inspect ./bin/www.js", - "dev:test:process": "cross-env NODE_ENV=dev DEBUG=lot-occupancy-system:* TEST_DATABASES=true nodemon ./bin/wwwProcess.js", - "dev:live": "cross-env NODE_ENV=dev DEBUG=lot-occupancy-system:* nodemon ./bin/www.js", + "dev:test:process": "cross-env NODE_ENV=dev DEBUG=lot-occupancy-system:* TEST_DATABASES=true nodemon --inspect ./bin/wwwProcess.js", + "dev:live": "cross-env NODE_ENV=dev DEBUG=lot-occupancy-system:* nodemon --inspect ./bin/www.js", "cy:open": "cypress open --config-file cypress.config.js", "cy:run": "cypress run --config-file cypress.config.js", "cy:run:firefox": "cypress run --config-file cypress.config.js --browser firefox", diff --git a/types/applicationTypes.d.ts b/types/applicationTypes.d.ts index a671e722..b904732f 100644 --- a/types/applicationTypes.d.ts +++ b/types/applicationTypes.d.ts @@ -1,6 +1,18 @@ export interface WorkerMessage { - messageType: 'clearCache'; - tableName: string; + messageType: string; timeMillis: number; pid: number; } +export interface ClearCacheWorkerMessage extends WorkerMessage { + messageType: 'clearCache'; + tableName: string; +} +export interface CacheLotIdsWorkerMessage extends WorkerMessage { + messageType: 'cacheLotIds'; + lotId: number; + nextLotId: number; +} +export interface ClearNextPreviousLotIdsCacheWorkerMessage extends WorkerMessage { + messageType: 'clearNextPreviousLotIdCache'; + lotId: number; +} diff --git a/types/applicationTypes.ts b/types/applicationTypes.ts index afd4bb37..e984c94a 100644 --- a/types/applicationTypes.ts +++ b/types/applicationTypes.ts @@ -1,6 +1,22 @@ export interface WorkerMessage { - messageType: 'clearCache' - tableName: string + messageType: string timeMillis: number pid: number } + +export interface ClearCacheWorkerMessage extends WorkerMessage { + messageType: 'clearCache' + tableName: string +} + +export interface CacheLotIdsWorkerMessage extends WorkerMessage { + messageType: 'cacheLotIds' + lotId: number + nextLotId: number +} + +export interface ClearNextPreviousLotIdsCacheWorkerMessage + extends WorkerMessage { + messageType: 'clearNextPreviousLotIdCache' + lotId: number +}