"dev": true
},
"@jest/types": {
- "version": "27.0.6",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.0.6.tgz",
- "integrity": "sha512-aSquT1qa9Pik26JK5/3rvnYb4bGtm1VFNesHKmNTwmPIgOrixvhL2ghIvFRNEpzy3gU+rUgjIF/KodbkFAl++g==",
+ "version": "27.1.0",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.1.0.tgz",
+ "integrity": "sha512-pRP5cLIzN7I7Vp6mHKRSaZD7YpBTK7hawx5si8trMKqk4+WOdK8NEKOTO2G8PKWD1HbKMVckVB6/XHh/olhf2g==",
"dev": true,
"requires": {
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/node": "*",
"@types/yargs": "^16.0.0",
"chalk": "^4.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
}
},
"@nearform/bubbleprof": {
"dev": true
},
"@types/stack-utils": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz",
- "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
+ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
"dev": true
},
"@types/tar": {
}
},
"@types/yargs": {
- "version": "16.0.3",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.3.tgz",
- "integrity": "sha512-YlFfTGS+zqCgXuXNV26rOIeETOkXnGQXP/pjjL9P0gO/EP9jTmc7pUBhx+jVEIxpq41RX33GQ7N3DzOSfZoglQ==",
+ "version": "16.0.4",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
+ "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==",
"dev": true,
"requires": {
"@types/yargs-parser": "*"
}
},
"@types/yargs-parser": {
- "version": "20.2.0",
- "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz",
- "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==",
+ "version": "20.2.1",
+ "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz",
+ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==",
"dev": true
},
"@typescript-eslint/eslint-plugin": {
}
},
"expect": {
- "version": "27.0.6",
- "resolved": "https://registry.npmjs.org/expect/-/expect-27.0.6.tgz",
- "integrity": "sha512-psNLt8j2kwg42jGBDSfAlU49CEZxejN1f1PlANWDZqIhBOVU/c2Pm888FcjWJzFewhIsNWfZJeLjUjtKGiPuSw==",
+ "version": "27.1.0",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-27.1.0.tgz",
+ "integrity": "sha512-9kJngV5hOJgkFil4F/uXm3hVBubUK2nERVfvqNNwxxuW8ZOUwSTTSysgfzckYtv/LBzj/LJXbiAF7okHCXgdug==",
"dev": true,
"requires": {
- "@jest/types": "^27.0.6",
+ "@jest/types": "^27.1.0",
"ansi-styles": "^5.0.0",
"jest-get-type": "^27.0.6",
- "jest-matcher-utils": "^27.0.6",
- "jest-message-util": "^27.0.6",
+ "jest-matcher-utils": "^27.1.0",
+ "jest-message-util": "^27.1.0",
"jest-regex-util": "^27.0.6"
},
"dependencies": {
}
},
"jest-diff": {
- "version": "27.0.6",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.0.6.tgz",
- "integrity": "sha512-Z1mqgkTCSYaFgwTlP/NUiRzdqgxmmhzHY1Tq17zL94morOHfHu3K4bgSgl+CR4GLhpV8VxkuOYuIWnQ9LnFqmg==",
+ "version": "27.1.0",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.1.0.tgz",
+ "integrity": "sha512-rjfopEYl58g/SZTsQFmspBODvMSytL16I+cirnScWTLkQVXYVZfxm78DFfdIIXc05RCYuGjxJqrdyG4PIFzcJg==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
"diff-sequences": "^27.0.6",
"jest-get-type": "^27.0.6",
- "pretty-format": "^27.0.6"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
+ "pretty-format": "^27.1.0"
}
},
"jest-get-type": {
"dev": true
},
"jest-matcher-utils": {
- "version": "27.0.6",
- "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.0.6.tgz",
- "integrity": "sha512-OFgF2VCQx9vdPSYTHWJ9MzFCehs20TsyFi6bIHbk5V1u52zJOnvF0Y/65z3GLZHKRuTgVPY4Z6LVePNahaQ+tA==",
+ "version": "27.1.0",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.1.0.tgz",
+ "integrity": "sha512-VmAudus2P6Yt/JVBRdTPFhUzlIN8DYJd+et5Rd9QDsO/Z82Z4iwGjo43U8Z+PTiz8CBvKvlb6Fh3oKy39hykkQ==",
"dev": true,
"requires": {
"chalk": "^4.0.0",
- "jest-diff": "^27.0.6",
+ "jest-diff": "^27.1.0",
"jest-get-type": "^27.0.6",
- "pretty-format": "^27.0.6"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
+ "pretty-format": "^27.1.0"
}
},
"jest-message-util": {
- "version": "27.0.6",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.0.6.tgz",
- "integrity": "sha512-rBxIs2XK7rGy+zGxgi+UJKP6WqQ+KrBbD1YMj517HYN3v2BG66t3Xan3FWqYHKZwjdB700KiAJ+iES9a0M+ixw==",
+ "version": "27.1.0",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.1.0.tgz",
+ "integrity": "sha512-Eck8NFnJ5Sg36R9XguD65cf2D5+McC+NF5GIdEninoabcuoOfWrID5qJhufq5FB0DRKoiyxB61hS7MKoMD0trQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.12.13",
- "@jest/types": "^27.0.6",
+ "@jest/types": "^27.1.0",
"@types/stack-utils": "^2.0.0",
"chalk": "^4.0.0",
"graceful-fs": "^4.2.4",
"micromatch": "^4.0.4",
- "pretty-format": "^27.0.6",
+ "pretty-format": "^27.1.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.3"
},
}
},
"@babel/helper-validator-identifier": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz",
- "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==",
+ "version": "7.14.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz",
+ "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==",
"dev": true
},
"@babel/highlight": {
}
}
},
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
- },
"graceful-fs": {
- "version": "4.2.6",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
- "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==",
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz",
+ "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==",
"dev": true
},
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
"micromatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
"dev": true
},
"pretty-format": {
- "version": "27.0.6",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.0.6.tgz",
- "integrity": "sha512-8tGD7gBIENgzqA+UBzObyWqQ5B778VIFZA/S66cclyd5YkFLYs2Js7gxDKf0MXtTc9zcS7t1xhdfcElJ3YIvkQ==",
+ "version": "27.1.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.1.0.tgz",
+ "integrity": "sha512-4aGaud3w3rxAO6OXmK3fwBFQ0bctIOG3/if+jYEFGNGIs0EvuidQm3bZ9mlP2/t9epLNC/12czabfy7TZNSwVA==",
"dev": true,
"requires": {
- "@jest/types": "^27.0.6",
+ "@jest/types": "^27.1.0",
"ansi-regex": "^5.0.0",
"ansi-styles": "^5.0.0",
"react-is": "^17.0.1"
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jsdoc": "^36.0.8",
"eslint-plugin-node": "^11.1.0",
- "expect": "^27.0.6",
+ "expect": "^27.1.0",
"mocha": "^9.1.0",
"mochawesome": "^6.2.2",
"npm-check": "^5.9.2",
preserveModulesRoot: 'src',
...!isDevelopmentBuild && { plugins: [terser({ numWorkers: 2 })] }
},
- external: ['basic-ftp', 'chalk', 'crypto', 'perf_hooks', 'fs', 'path', 'poolifier', 'tar', 'url', 'uuid', 'ws', 'winston-daily-rotate-file', 'winston/lib/winston/transports', 'winston', 'worker_threads'],
+ external: ['basic-ftp', 'chalk', 'crypto', 'mongodb', 'perf_hooks', 'fs', 'path', 'poolifier', 'tar', 'url', 'uuid', 'ws', 'winston-daily-rotate-file', 'winston/lib/winston/transports', 'winston', 'worker_threads'],
plugins: [
json(),
typescript({
-import { ChargingStationWorkerData, WorkerEvents, WorkerMessage } from '../types/Worker';
+import { ChargingStationWorkerData, WorkerMessage, WorkerMessageEvents } from '../types/Worker';
import Configuration from '../utils/Configuration';
import { Storage } from '../utils/performance-storage/Storage';
if (isMainThread && !this.started) {
try {
let numStationsTotal = 0;
+ await Bootstrap.storage.open();
await Bootstrap.workerImplementation.start();
// Start ChargingStation object in worker thread
if (Configuration.getStationTemplateURLs()) {
public async stop(): Promise<void> {
if (isMainThread && this.started) {
await Bootstrap.workerImplementation.stop();
+ await Bootstrap.storage.close();
}
this.started = false;
}
await this.start();
}
- private initWorkerImplementation() {
+ private initWorkerImplementation(): void {
Bootstrap.workerImplementation = WorkerFactory.getWorkerImplementation<ChargingStationWorkerData>(this.workerScript, Configuration.getWorkerProcess(),
{
startDelay: Configuration.getWorkerStartDelay(),
poolOptions: {
workerChoiceStrategy: Configuration.getWorkerPoolStrategy()
}
- }, (msg: WorkerMessage) => {
- if (msg.id === WorkerEvents.PERFORMANCE_STATISTICS) {
- Bootstrap.storage.storePerformanceStatistics(msg.data);
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
+ }, async (msg: WorkerMessage) => {
+ if (msg.id === WorkerMessageEvents.PERFORMANCE_STATISTICS) {
+ await Bootstrap.storage.storePerformanceStatistics(msg.data);
}
});
}
}
this.stationInfo.powerDivider = this.getPowerDivider();
if (this.getEnableStatistics()) {
- this.performanceStatistics = new PerformanceStatistics(this.stationInfo.chargingStationId);
+ this.performanceStatistics = new PerformanceStatistics(this.stationInfo.chargingStationId, this.wsConnectionUrl);
}
}
return !Utils.isUndefined(this.stationInfo.reconnectExponentialDelay) ? this.stationInfo.reconnectExponentialDelay : false;
}
- private async reconnect(error: any): Promise<void> {
+ private async reconnect(error: unknown): Promise<void> {
// Stop WebSocket ping
this.stopWebSocketPing();
// Stop heartbeat
// Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
-import { ChargingStationWorkerData, WorkerEvents, WorkerMessage } from '../types/Worker';
+import { ChargingStationWorkerData, WorkerMessage, WorkerMessageEvents } from '../types/Worker';
import { parentPort, workerData } from 'worker_threads';
import ChargingStation from './ChargingStation';
*/
function addMessageListener(): void {
parentPort?.on('message', (message: WorkerMessage) => {
- if (message.id === WorkerEvents.START_WORKER_ELEMENT) {
+ if (message.id === WorkerMessageEvents.START_WORKER_ELEMENT) {
startChargingStation(message.data);
}
});
import { CircularArray } from '../utils/CircularArray';
+import { URL } from 'url';
export interface StatisticsData {
countRequest: number;
export default interface Statistics {
id: string;
+ URI: string;
createdAt: Date;
lastUpdatedAt?: Date;
statisticsData: Record<string, StatisticsData>;
MONGO_DB = 'mongodb'
}
+export enum DBType {
+ MONGO_DB = 'MongoDB'
+}
+
}
export interface WorkerMessage {
- id: WorkerEvents;
+ id: WorkerMessageEvents;
data: any;
}
-export enum WorkerEvents {
+export enum WorkerMessageEvents {
START_WORKER_ELEMENT = 'startWorkerElement',
STOP_WORKER_ELEMENT = 'stopWorkerElement',
PERFORMANCE_STATISTICS = 'performanceStatistics'
MeterValueMeasurand.POWER_ACTIVE_IMPORT, MeterValueMeasurand.CURRENT_IMPORT, MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER]);
static readonly DEFAULT_FLUCTUATION_PERCENT = 5;
+
+ static readonly PERFORMANCE_RECORDS_FILETYPE = 'Performance records';
+ static readonly DEFAULT_PERFORMANCE_RECORDS_DB_NAME = 'charging-stations-simulator';
+ static readonly PERFORMANCE_RECORDS_TABLE = 'performanceRecords';
}
import Configuration from './Configuration';
import { MessageType } from '../types/ocpp/MessageType';
+import { URL } from 'url';
import Utils from './Utils';
-import { WorkerEvents } from '../types/Worker';
+import { WorkerMessageEvents } from '../types/Worker';
import logger from './Logger';
import { parentPort } from 'worker_threads';
private statistics: Statistics;
private displayInterval: NodeJS.Timeout;
- public constructor(objId: string) {
+ public constructor(objId: string, URI: URL) {
this.objId = objId;
this.initializePerformanceObserver();
- this.statistics = { id: this.objId ?? 'Object id not specified', createdAt: new Date(), statisticsData: {} };
+ this.statistics = { id: this.objId ?? 'Object id not specified', URI: URI.toString(), createdAt: new Date(), statisticsData: {} };
}
public static beginMeasure(id: string): string {
this.statistics.statisticsData[entryName].ninetyFiveThPercentileTimeMeasurement = this.percentile(this.statistics.statisticsData[entryName].timeMeasurementSeries, 95);
this.statistics.statisticsData[entryName].stdDevTimeMeasurement = this.stdDeviation(this.statistics.statisticsData[entryName].timeMeasurementSeries);
if (Configuration.getPerformanceStorage().enabled) {
- parentPort.postMessage({ id: WorkerEvents.PERFORMANCE_STATISTICS, data: this.statistics });
+ parentPort.postMessage({ id: WorkerMessageEvents.PERFORMANCE_STATISTICS, data: this.statistics });
}
}
+import Constants from '../Constants';
import FileUtils from '../FileUtils';
import Statistics from '../../types/Statistics';
import { Storage } from './Storage';
import path from 'path';
export class JSONFileStorage extends Storage {
+ private fd: number | null = null;
+
constructor(storageURI: string, logPrefix: string) {
super(storageURI, logPrefix);
+ this.dbName = path.join(path.resolve(__dirname, '../../../'), this.storageURI.pathname.replace(/(?:^\/)|(?:\/$)/g, ''));
}
public storePerformanceStatistics(performanceStatistics: Statistics): void {
- const performanceJSONFilePath = path.join(path.resolve(__dirname, '../../../'), this.storageURI.pathname.replace(/(?:^\/)|(?:\/$)/g, ''));
- if (!fs.existsSync(performanceJSONFilePath)) {
- this.open(performanceJSONFilePath);
- }
- fs.readFile(performanceJSONFilePath, 'utf-8', (error, data) => {
+ this.checkPerformanceRecordsFile();
+ fs.readFile(this.dbName, 'utf-8', (error, data) => {
if (error) {
- FileUtils.handleFileException(this.logPrefix, 'Performance measurements', performanceJSONFilePath, error);
+ FileUtils.handleFileException(this.logPrefix, Constants.PERFORMANCE_RECORDS_FILETYPE, this.dbName, error);
} else {
- const performanceRecords: Statistics[] = data ? JSON.parse(data.toString()) as Statistics[] : [];
+ const performanceRecords: Statistics[] = data ? JSON.parse(data) as Statistics[] : [];
performanceRecords.push(performanceStatistics);
- fs.writeFile(performanceJSONFilePath, JSON.stringify(performanceRecords, null, 2), 'utf-8', (err) => {
+ fs.writeFile(this.dbName, JSON.stringify(performanceRecords, null, 2), 'utf-8', (err) => {
if (err) {
- FileUtils.handleFileException(this.logPrefix, 'Performance measurements', performanceJSONFilePath, err);
+ FileUtils.handleFileException(this.logPrefix, Constants.PERFORMANCE_RECORDS_FILETYPE, this.dbName, err);
}
});
}
});
}
- private open(filePath: string): void {
+ public open(): void {
try {
- fs.openSync(filePath, 'w+');
+ this.fd = fs.openSync(this.dbName, 'a+');
} catch (error) {
- FileUtils.handleFileException(this.logPrefix, 'Performance measurements', filePath, error);
+ FileUtils.handleFileException(this.logPrefix, Constants.PERFORMANCE_RECORDS_FILETYPE, this.dbName, error);
+ }
+ }
+
+ public close(): void {
+ try {
+ if (this.fd) {
+ fs.closeSync(this.fd);
+ this.fd = null;
+ }
+ } catch (error) {
+ FileUtils.handleFileException(this.logPrefix, Constants.PERFORMANCE_RECORDS_FILETYPE, this.dbName, error);
+ }
+ }
+
+ private checkPerformanceRecordsFile(): void {
+ if (!this.fd) {
+ throw new Error(`${this.logPrefix} Performance records '${this.dbName}' file descriptor not found`);
}
}
}
+import Constants from '../Constants';
+import { DBType } from '../../types/Storage';
+import { MongoClient } from 'mongodb';
import Statistics from '../../types/Statistics';
import { Storage } from './Storage';
export class MongoDBStorage extends Storage {
+ private client: MongoClient;
+ private connected: boolean;
+
constructor(storageURI: string, logPrefix: string) {
super(storageURI, logPrefix);
+ this.client = new MongoClient(this.storageURI.toString());
+ this.connected = false;
+ this.dbName = this.storageURI.pathname.replace(/(?:^\/)|(?:\/$)/g, '') ?? Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME;
}
- public storePerformanceStatistics(performanceStatistics: Statistics): void {
- throw new Error('Method not yet implemented');
+ public async storePerformanceStatistics(performanceStatistics: Statistics): Promise<void> {
+ try {
+ this.checkDBConnection();
+ await this.client.db(this.dbName).collection<Statistics>(Constants.PERFORMANCE_RECORDS_TABLE).insertOne(performanceStatistics);
+ } catch (error) {
+ this.handleDBError(DBType.MONGO_DB, error, Constants.PERFORMANCE_RECORDS_TABLE);
+ }
}
- private open(): void {}
+ public async open(): Promise<void> {
+ try {
+ if (!this.connected) {
+ await this.client.connect();
+ this.connected = true;
+ }
+ } catch (error) {
+ this.handleDBError(DBType.MONGO_DB, error);
+ }
+ }
- private close(): void {}
+ public async close(): Promise<void> {
+ try {
+ if (this.connected) {
+ await this.client.close();
+ this.connected = false;
+ }
+ } catch (error) {
+ this.handleDBError(DBType.MONGO_DB, error);
+ }
+ }
+
+ private checkDBConnection() {
+ if (!this.connected) {
+ throw new Error(`${this.logPrefix} ${DBType.MONGO_DB} connection not opened while trying to issue a request`);
+ }
+ }
}
+import { DBType } from '../../types/Storage';
import Statistics from '../../types/Statistics';
import { URL } from 'url';
+import logger from '../Logger';
export abstract class Storage {
- protected storageURI: URL;
- protected logPrefix: string;
+ protected readonly storageURI: URL;
+ protected readonly logPrefix: string;
+ protected dbName: string;
constructor(storageURI: string, logPrefix: string) {
this.storageURI = new URL(storageURI);
this.logPrefix = logPrefix;
}
- public abstract storePerformanceStatistics(performanceStatistics: Statistics): void;
+ protected handleDBError(DBEngine: DBType, error: Error, table?: string): void {
+ logger.error(`${this.logPrefix} ${DBEngine} error${table && ` in table or collection ${table}`} %j`, error);
+ }
+
+ public abstract open(): void | Promise<void>;
+ public abstract close(): void | Promise<void>;
+ public abstract storePerformanceStatistics(performanceStatistics: Statistics): void | Promise<void>;
}
// Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
-import { WorkerEvents, WorkerSetElement } from '../types/Worker';
+import { WorkerMessageEvents, WorkerSetElement } from '../types/Worker';
import Utils from '../utils/Utils';
import { Worker } from 'worker_threads';
// Start worker sequentially to optimize memory at startup
await Utils.sleep(this.workerStartDelay);
}
- this.getLastWorker().postMessage({ id: WorkerEvents.START_WORKER_ELEMENT, data: elementData });
+ this.getLastWorker().postMessage({ id: WorkerMessageEvents.START_WORKER_ELEMENT, data: elementData });
this.getLastWorkerSetElement().numberOfWorkerElements++;
}