clear lot cache messaging

deepsource-autofix-76c6eb20
Dan Gowans 2023-03-27 11:03:43 -04:00
parent e7b4753123
commit 18f5dc7103
11 changed files with 184 additions and 31 deletions

View File

@ -25,7 +25,6 @@ for (let index = 0; index < processCount; index += 1) {
activeWorkers.set(worker.process.pid, worker); activeWorkers.set(worker.process.pid, worker);
} }
cluster.on('message', (worker, message) => { cluster.on('message', (worker, message) => {
if (message?.messageType === 'clearCache') {
for (const [pid, worker] of activeWorkers.entries()) { for (const [pid, worker] of activeWorkers.entries()) {
if (worker === undefined || pid === message.pid) { if (worker === undefined || pid === message.pid) {
continue; continue;
@ -33,7 +32,6 @@ cluster.on('message', (worker, message) => {
debug('Relaying message to workers'); debug('Relaying message to workers');
worker.send(message); worker.send(message);
} }
}
}); });
cluster.on('exit', (worker, code, signal) => { cluster.on('exit', (worker, code, signal) => {
debug(`Worker ${worker.process.pid.toString()} has been killed`); debug(`Worker ${worker.process.pid.toString()} has been killed`);

View File

@ -45,7 +45,6 @@ for (let index = 0; index < processCount; index += 1) {
} }
cluster.on('message', (worker, message: WorkerMessage) => { cluster.on('message', (worker, message: WorkerMessage) => {
if (message?.messageType === 'clearCache') {
for (const [pid, worker] of activeWorkers.entries()) { for (const [pid, worker] of activeWorkers.entries()) {
if (worker === undefined || pid === message.pid) { if (worker === undefined || pid === message.pid) {
continue continue
@ -54,7 +53,6 @@ cluster.on('message', (worker, message: WorkerMessage) => {
debug('Relaying message to workers') debug('Relaying message to workers')
worker.send(message) worker.send(message)
} }
}
}) })
cluster.on('exit', (worker, code, signal) => { cluster.on('exit', (worker, code, signal) => {

View File

@ -18,7 +18,7 @@ import { getWorkOrderTypes as getWorkOrderTypesFromDatabase } from './lotOccupan
import { getWorkOrderMilestoneTypes as getWorkOrderMilestoneTypesFromDatabase } from './lotOccupancyDB/getWorkOrderMilestoneTypes.js' import { getWorkOrderMilestoneTypes as getWorkOrderMilestoneTypesFromDatabase } from './lotOccupancyDB/getWorkOrderMilestoneTypes.js'
import type * as recordTypes from '../types/recordTypes' import type * as recordTypes from '../types/recordTypes'
import type { WorkerMessage } from '../types/applicationTypes' import type { ClearCacheWorkerMessage } from '../types/applicationTypes'
import Debug from 'debug' import Debug from 'debug'
const debug = Debug(`lot-occupancy-system:functions.cache:${process.pid}`) const debug = Debug(`lot-occupancy-system:functions.cache:${process.pid}`)
@ -343,7 +343,7 @@ export function clearCacheByTableName(
try { try {
if (relayMessage && cluster.isWorker) { if (relayMessage && cluster.isWorker) {
const workerMessage: WorkerMessage = { const workerMessage: ClearCacheWorkerMessage = {
messageType: 'clearCache', messageType: 'clearCache',
tableName, tableName,
timeMillis: Date.now(), timeMillis: Date.now(),
@ -357,7 +357,7 @@ export function clearCacheByTableName(
} catch {} } catch {}
} }
process.on('message', (message: WorkerMessage) => { process.on('message', (message: ClearCacheWorkerMessage) => {
if (message.messageType === 'clearCache' && message.pid !== process.pid) { if (message.messageType === 'clearCache' && message.pid !== process.pid) {
debug(`Clearing cache: ${message.tableName}`) debug(`Clearing cache: ${message.tableName}`)
clearCacheByTableName(message.tableName, false) clearCacheByTableName(message.tableName, false)

View File

@ -1,3 +1,3 @@
export declare function getNextLotId(lotId: number): Promise<number | undefined>; export declare function getNextLotId(lotId: number): Promise<number | undefined>;
export declare function getPreviousLotId(lotId: number): Promise<number | undefined>; export declare function getPreviousLotId(lotId: number): Promise<number | undefined>;
export declare function clearNextPreviousLotIdCache(lotId?: number): void; export declare function clearNextPreviousLotIdCache(lotId: number | -1, relayMessage?: boolean): void;

View File

@ -1,15 +1,32 @@
import cluster from 'node:cluster';
import NodeCache from 'node-cache'; import NodeCache from 'node-cache';
import getPreviousLotIdFromDatabase from './lotOccupancyDB/getPreviousLotId.js'; import getPreviousLotIdFromDatabase from './lotOccupancyDB/getPreviousLotId.js';
import getNextLotIdFromDatabase from './lotOccupancyDB/getNextLotId.js'; import getNextLotIdFromDatabase from './lotOccupancyDB/getNextLotId.js';
import Debug from 'debug';
const debug = Debug(`lot-occupancy-system:functions.lots:${process.pid}`);
const cacheOptions = { const cacheOptions = {
stdTTL: 2 * 60, stdTTL: 2 * 60,
useClones: false useClones: false
}; };
const previousLotIdCache = new NodeCache(cacheOptions); const previousLotIdCache = new NodeCache(cacheOptions);
const nextLotIdCache = new NodeCache(cacheOptions); const nextLotIdCache = new NodeCache(cacheOptions);
function cacheLotIds(lotId, nextLotId) { function cacheLotIds(lotId, nextLotId, relayMessage = true) {
previousLotIdCache.set(nextLotId, lotId); previousLotIdCache.set(nextLotId, lotId);
nextLotIdCache.set(lotId, nextLotId); 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) { export async function getNextLotId(lotId) {
let nextLotId = nextLotIdCache.get(lotId); let nextLotId = nextLotIdCache.get(lotId);
@ -31,8 +48,8 @@ export async function getPreviousLotId(lotId) {
} }
return previousLotId; return previousLotId;
} }
export function clearNextPreviousLotIdCache(lotId) { export function clearNextPreviousLotIdCache(lotId, relayMessage = true) {
if (lotId === undefined) { if (lotId === undefined || lotId === -1) {
previousLotIdCache.flushAll(); previousLotIdCache.flushAll();
nextLotIdCache.flushAll(); nextLotIdCache.flushAll();
return; return;
@ -47,4 +64,33 @@ export function clearNextPreviousLotIdCache(lotId) {
previousLotIdCache.del(nextLotId); previousLotIdCache.del(nextLotId);
nextLotIdCache.del(lotId); 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;
}
}
}
});

View File

@ -1,8 +1,18 @@
import cluster from 'node:cluster'
import NodeCache from 'node-cache' import NodeCache from 'node-cache'
import getPreviousLotIdFromDatabase from './lotOccupancyDB/getPreviousLotId.js' import getPreviousLotIdFromDatabase from './lotOccupancyDB/getPreviousLotId.js'
import getNextLotIdFromDatabase from './lotOccupancyDB/getNextLotId.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 = { const cacheOptions: NodeCache.Options = {
stdTTL: 2 * 60, // two minutes stdTTL: 2 * 60, // two minutes
useClones: false useClones: false
@ -12,9 +22,29 @@ const previousLotIdCache = new NodeCache(cacheOptions)
const nextLotIdCache = 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) previousLotIdCache.set(nextLotId, lotId)
nextLotIdCache.set(lotId, nextLotId) 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<number | undefined> { export async function getNextLotId(lotId: number): Promise<number | undefined> {
@ -47,8 +77,11 @@ export async function getPreviousLotId(
return previousLotId return previousLotId
} }
export function clearNextPreviousLotIdCache(lotId?: number): void { export function clearNextPreviousLotIdCache(
if (lotId === undefined) { lotId: number | -1,
relayMessage = true
): void {
if (lotId === undefined || lotId === -1) {
previousLotIdCache.flushAll() previousLotIdCache.flushAll()
nextLotIdCache.flushAll() nextLotIdCache.flushAll()
return return
@ -67,4 +100,43 @@ export function clearNextPreviousLotIdCache(lotId?: number): void {
previousLotIdCache.del(nextLotId) previousLotIdCache.del(nextLotId)
nextLotIdCache.del(lotId) 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
}
}
}
}
)

View File

@ -1,6 +1,7 @@
import { acquireConnection } from './pool.js'; import { acquireConnection } from './pool.js';
import { addOrUpdateLotField } from './addOrUpdateLotField.js'; import { addOrUpdateLotField } from './addOrUpdateLotField.js';
import { deleteLotField } from './deleteLotField.js'; import { deleteLotField } from './deleteLotField.js';
import { clearNextPreviousLotIdCache } from '../functions.lots.js';
export async function updateLot(lotForm, requestSession) { export async function updateLot(lotForm, requestSession) {
const database = await acquireConnection(); const database = await acquireConnection();
const rightNowMillis = Date.now(); const rightNowMillis = Date.now();
@ -32,6 +33,9 @@ export async function updateLot(lotForm, requestSession) {
} }
} }
database.release(); database.release();
clearNextPreviousLotIdCache(typeof lotForm.lotId === 'number'
? lotForm.lotId
: Number.parseInt(lotForm.lotId, 10));
return result.changes > 0; return result.changes > 0;
} }
export async function updateLotStatus(lotId, lotStatusId, requestSession) { export async function updateLotStatus(lotId, lotStatusId, requestSession) {

View File

@ -5,6 +5,7 @@ import { addOrUpdateLotField } from './addOrUpdateLotField.js'
import { deleteLotField } from './deleteLotField.js' import { deleteLotField } from './deleteLotField.js'
import type * as recordTypes from '../../types/recordTypes' import type * as recordTypes from '../../types/recordTypes'
import { clearNextPreviousLotIdCache } from '../functions.lots.js'
interface UpdateLotForm { interface UpdateLotForm {
lotId: string | number lotId: string | number
@ -87,6 +88,12 @@ export async function updateLot(
database.release() database.release()
clearNextPreviousLotIdCache(
typeof lotForm.lotId === 'number'
? lotForm.lotId
: Number.parseInt(lotForm.lotId, 10)
)
return result.changes > 0 return result.changes > 0
} }

View File

@ -10,8 +10,8 @@
"scripts": { "scripts": {
"start": "cross-env NODE_ENV=production node ./bin/www.js", "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": "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: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 ./bin/www.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:open": "cypress open --config-file cypress.config.js",
"cy:run": "cypress run --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", "cy:run:firefox": "cypress run --config-file cypress.config.js --browser firefox",

View File

@ -1,6 +1,18 @@
export interface WorkerMessage { export interface WorkerMessage {
messageType: 'clearCache'; messageType: string;
tableName: string;
timeMillis: number; timeMillis: number;
pid: 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;
}

View File

@ -1,6 +1,22 @@
export interface WorkerMessage { export interface WorkerMessage {
messageType: 'clearCache' messageType: string
tableName: string
timeMillis: number timeMillis: number
pid: 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
}