From 6d9abcc2b7b384773348c64bf0f7fc4dc5aad061 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Mon, 4 Oct 2021 22:23:40 +0200 Subject: [PATCH] Fix OCPP message sending timeout handling code MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit --- src/charging-station/ChargingStation.ts | 2 +- .../ocpp/OCPPRequestService.ts | 7 ++++--- src/utils/Constants.ts | 2 +- src/utils/Utils.ts | 18 ++++++++++++++++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/charging-station/ChargingStation.ts b/src/charging-station/ChargingStation.ts index dde84562..6e57931b 100644 --- a/src/charging-station/ChargingStation.ts +++ b/src/charging-station/ChargingStation.ts @@ -703,7 +703,7 @@ export default class ChargingStation { } } catch (error) { // Log - logger.error('%s Incoming OCPP message %j matching cached request %j processing error %j', this.logPrefix(), data, this.requests.get(messageId), error); + logger.error('%s Incoming OCPP message %j matching cached request %j processing error %j', this.logPrefix(), data.toString(), this.requests.get(messageId), error); // Send error messageType === MessageType.CALL_MESSAGE && await this.ocppRequestService.sendError(messageId, error, commandName); } diff --git a/src/charging-station/ocpp/OCPPRequestService.ts b/src/charging-station/ocpp/OCPPRequestService.ts index 4996b9e7..5d767f0c 100644 --- a/src/charging-station/ocpp/OCPPRequestService.ts +++ b/src/charging-station/ocpp/OCPPRequestService.ts @@ -12,6 +12,7 @@ import { MeterValue } from '../../types/ocpp/MeterValues'; import OCPPError from './OCPPError'; import OCPPResponseService from './OCPPResponseService'; import PerformanceStatistics from '../../performance/PerformanceStatistics'; +import Utils from '../../utils/Utils'; import logger from '../../utils/Logger'; export default abstract class OCPPRequestService { @@ -28,7 +29,7 @@ export default abstract class OCPPRequestService { // eslint-disable-next-line @typescript-eslint/no-this-alias const self = this; // Send a message through wsConnection - return new Promise((resolve, reject) => { + return Utils.promiseWithTimeout(new Promise((resolve, reject) => { const messageToSend = this.buildMessageToSend(messageId, commandParams, messageType, commandName, responseCallback, rejectCallback); if (this.chargingStation.getEnableStatistics()) { this.chargingStation.performanceStatistics.addRequestStatistic(commandName, messageType); @@ -58,8 +59,6 @@ export default abstract class OCPPRequestService { // Yes: send Ok return resolve(commandParams); } - // Send timeout - setTimeout(() => rejectCallback(new OCPPError(ErrorType.GENERIC_ERROR, `Timeout for message id '${messageId}' with content '${messageToSend}'`, commandParams?.details ?? {}), false), Constants.OCPP_SOCKET_TIMEOUT); /** * Function that will receive the request's response @@ -91,6 +90,8 @@ export default abstract class OCPPRequestService { self.chargingStation.requests.delete(messageId); reject(error); } + }), Constants.OCPP_WEBSOCKET_TIMEOUT, new OCPPError(ErrorType.GENERIC_ERROR, `Timeout for message id '${messageId}'`, commandParams?.details ?? {}), () => { + messageType === MessageType.CALL_MESSAGE && this.chargingStation.requests.delete(messageId); }); } diff --git a/src/utils/Constants.ts b/src/utils/Constants.ts index f7705963..c10a320b 100644 --- a/src/utils/Constants.ts +++ b/src/utils/Constants.ts @@ -26,7 +26,7 @@ export default class Constants { static readonly OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED = Object.freeze({ status: TriggerMessageStatus.NOT_IMPLEMENTED }); static readonly OCPP_DEFAULT_BOOT_NOTIFICATION_INTERVAL = 60000; // Ms - static readonly OCPP_SOCKET_TIMEOUT = 60000; // Ms + static readonly OCPP_WEBSOCKET_TIMEOUT = 60000; // Ms static readonly OCPP_TRIGGER_MESSAGE_DELAY = 2000; // Ms static readonly CHARGING_STATION_DEFAULT_RESET_TIME = 60000; // Ms diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index b04814a7..6133177f 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -235,6 +235,24 @@ export default class Utils { return Configuration.getWorkerProcess() === WorkerProcessType.DYNAMIC_POOL; } + public static async promiseWithTimeout( + promise: Promise, + timeoutMs: number, + timeoutError: Error, + timeoutCallback: () => void = () => { /* This is intentional */ } + ): Promise { + // Create a timeout promise that rejects in timeout milliseconds + const timeoutPromise = new Promise((_, reject) => { + setTimeout(() => { + timeoutCallback; + reject(timeoutError); + }, timeoutMs); + }); + + // Returns a race between timeout promise and the passed promise + return Promise.race([promise, timeoutPromise]); + } + /** * Generate a cryptographically secure random number in the [0,1[ range * -- 2.34.1