perf: cache request promise after sending it
authorJérôme Benoit <jerome.benoit@sap.com>
Sun, 19 Nov 2023 09:51:04 +0000 (10:51 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Sun, 19 Nov 2023 09:51:04 +0000 (10:51 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
src/charging-station/ocpp/OCPPRequestService.ts
ui/web/src/composables/UIClient.ts

index b1b3edfa4b3018d9ee7ef47eadb43a93e66a8e26..a6993ccd0c311628e3324a0fb3ed4d87c5930136 100644 (file)
@@ -93,8 +93,6 @@ export abstract class OCPPRequestService {
       messagePayload: JsonType | OCPPError,
       messageType: MessageType,
       commandName: RequestCommand | IncomingRequestCommand,
-      responseCallback: ResponseCallback,
-      errorCallback: ErrorCallback,
     ) => string;
     this.validateRequestPayload = this.validateRequestPayload.bind(this) as <T extends JsonType>(
       chargingStation: ChargingStation,
@@ -381,8 +379,6 @@ export abstract class OCPPRequestService {
           messagePayload,
           messageType,
           commandName,
-          responseCallback,
-          errorCallback,
         );
         // Check if wsConnection opened
         if (chargingStation.isWebSocketConnectionOpened() === true) {
@@ -399,27 +395,23 @@ export abstract class OCPPRequestService {
             );
           }, OCPPConstants.OCPP_WEBSOCKET_TIMEOUT);
           chargingStation.wsConnection?.send(messageToSend, (error?: Error) => {
-            if (error && params?.skipBufferingOnError === false) {
-              // Buffer
-              chargingStation.bufferMessage(messageToSend);
-              // Reject and keep request in the cache
-              return reject(
-                new OCPPError(
-                  ErrorType.GENERIC_ERROR,
-                  `WebSocket errored for buffered message id '${messageId}' with content '${messageToSend}'`,
-                  commandName,
-                  { name: error.name, message: error.message, stack: error.stack } ??
-                    Constants.EMPTY_FROZEN_OBJECT,
-                ),
-              );
-            } else if (error) {
+            clearTimeout(sendTimeout);
+            if (error) {
               const ocppError = new OCPPError(
                 ErrorType.GENERIC_ERROR,
-                `WebSocket errored for non buffered message id '${messageId}' with content '${messageToSend}'`,
+                `WebSocket errored for ${
+                  params?.skipBufferingOnError === false ? '' : 'non '
+                }buffered message id '${messageId}' with content '${messageToSend}'`,
                 commandName,
                 { name: error.name, message: error.message, stack: error.stack } ??
                   Constants.EMPTY_FROZEN_OBJECT,
               );
+              if (params?.skipBufferingOnError === false) {
+                // Buffer
+                chargingStation.bufferMessage(messageToSend);
+                // Reject and keep request in the cache
+                return reject(ocppError);
+              }
               // Reject response
               if (messageType !== MessageType.CALL_MESSAGE) {
                 return reject(ocppError);
@@ -427,39 +419,49 @@ export abstract class OCPPRequestService {
               // Reject and remove request from the cache
               return errorCallback(ocppError, false);
             }
-            clearTimeout(sendTimeout);
           });
+          if (messageType === MessageType.CALL_MESSAGE) {
+            this.cacheRequestPromise(
+              chargingStation,
+              responseCallback,
+              errorCallback,
+              messageId,
+              messagePayload as JsonType,
+              commandName,
+            );
+          }
           logger.debug(
             `${chargingStation.logPrefix()} >> Command '${commandName}' sent ${OCPPServiceUtils.getMessageTypeString(
               messageType,
             )} payload: ${messageToSend}`,
           );
           PerformanceStatistics.endMeasure(commandName, beginId);
-        } else if (params?.skipBufferingOnError === false) {
-          // Buffer
-          chargingStation.bufferMessage(messageToSend);
+        } else {
+          if (params?.skipBufferingOnError === false) {
+            // Buffer
+            chargingStation.bufferMessage(messageToSend);
+            if (messageType === MessageType.CALL_MESSAGE) {
+              this.cacheRequestPromise(
+                chargingStation,
+                responseCallback,
+                errorCallback,
+                messageId,
+                messagePayload as JsonType,
+                commandName,
+              );
+            }
+          }
           // Reject and keep request in the cache
           return reject(
             new OCPPError(
               ErrorType.GENERIC_ERROR,
-              `WebSocket closed for buffered message id '${messageId}' with content '${messageToSend}'`,
+              `WebSocket closed for ${
+                params?.skipBufferingOnError === false ? '' : 'non '
+              }buffered message id '${messageId}' with content '${messageToSend}'`,
               commandName,
               (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FROZEN_OBJECT,
             ),
           );
-        } else {
-          const ocppError = new OCPPError(
-            ErrorType.GENERIC_ERROR,
-            `WebSocket closed for non buffered message id '${messageId}' with content '${messageToSend}'`,
-            commandName,
-            (messagePayload as JsonObject)?.details ?? Constants.EMPTY_FROZEN_OBJECT,
-          );
-          // Reject response
-          if (messageType !== MessageType.CALL_MESSAGE) {
-            return reject(ocppError);
-          }
-          // Reject and remove request from the cache
-          return errorCallback(ocppError, false);
         }
         // Resolve response
         if (messageType !== MessageType.CALL_MESSAGE) {
@@ -480,8 +482,6 @@ export abstract class OCPPRequestService {
     messagePayload: JsonType | OCPPError,
     messageType: MessageType,
     commandName: RequestCommand | IncomingRequestCommand,
-    responseCallback: ResponseCallback,
-    errorCallback: ErrorCallback,
   ): string {
     let messageToSend: string;
     // Type of message
@@ -490,12 +490,6 @@ export abstract class OCPPRequestService {
       case MessageType.CALL_MESSAGE:
         // Build request
         this.validateRequestPayload(chargingStation, commandName, messagePayload as JsonType);
-        chargingStation.requests.set(messageId, [
-          responseCallback,
-          errorCallback,
-          commandName,
-          messagePayload as JsonType,
-        ]);
         messageToSend = JSON.stringify([
           messageType,
           messageId,
@@ -528,6 +522,22 @@ export abstract class OCPPRequestService {
     return messageToSend;
   }
 
+  private cacheRequestPromise(
+    chargingStation: ChargingStation,
+    responseCallback: ResponseCallback,
+    errorCallback: ErrorCallback,
+    messageId: string,
+    messagePayload: JsonType,
+    commandName: RequestCommand | IncomingRequestCommand,
+  ): void {
+    chargingStation.requests.set(messageId, [
+      responseCallback,
+      errorCallback,
+      commandName,
+      messagePayload,
+    ]);
+  }
+
   // eslint-disable-next-line @typescript-eslint/no-unused-vars
   public abstract requestHandler<ReqType extends JsonType, ResType extends JsonType>(
     chargingStation: ChargingStation,
index 745accdfb8d0e60aa0883bd7133656cf6d4e9654..841ec3dca8c42510c3ce504c05dbe42c45773adc 100644 (file)
@@ -159,7 +159,9 @@ export class UIClient {
         }, 60 * 1000);
         try {
           this.ws.send(msg);
+          this.setResponseHandler(uuid, command, resolve, reject);
         } catch (error) {
+          this.deleteResponseHandler(uuid);
           reject(error);
         } finally {
           clearTimeout(sendTimeout);
@@ -167,8 +169,6 @@ export class UIClient {
       } else {
         throw new Error(`Send request '${command}' message: connection not opened`);
       }
-
-      this.setResponseHandler(uuid, command, resolve, reject);
     });
   }
 
@@ -182,15 +182,18 @@ export class UIClient {
     const [uuid, responsePayload] = response;
 
     if (this.responseHandlers.has(uuid) === true) {
+      const { procedureName, resolve, reject } = this.getResponseHandler(uuid)!;
       switch (responsePayload.status) {
         case ResponseStatus.SUCCESS:
-          this.getResponseHandler(uuid)?.resolve(responsePayload);
+          resolve(responsePayload);
           break;
         case ResponseStatus.FAILURE:
-          this.getResponseHandler(uuid)?.reject(responsePayload);
+          reject(responsePayload);
           break;
         default:
-          console.error(`Response status not supported: ${responsePayload.status}`);
+          console.error(
+            `Response status for procedure '${procedureName}' not supported: '${responsePayload.status}'`,
+          );
       }
       this.deleteResponseHandler(uuid);
     } else {