Skip to content

Race Condition in Component Initialization and OCPP Server Startup #2909

@katsuya

Description

@katsuya

Description

We have identified a bug where a race condition exists between the initialization of components and the startup of the OCPP server.

To address this issue, we have created the following patch. However, we are not convinced this is the optimal solution and would appreciate any suggestions for a better approach.

This is a rather ad-hoc fix that delays the startup of MyJsonServer by three minutes, allowing it to start receiving requests from the charge station only after the component initialization has completed. Clearly, this will fail if the component initialization takes longer than three minutes.

From aefca39f7ac1310e0139a462ab79413607c94c13 Mon Sep 17 00:00:00 2001
From: Katsuya Oda <[email protected]>
Date: Sat, 9 Nov 2024 16:05:15 +0900
Subject: [PATCH] fix: delay ocpp server straup to fix race condition

---
 .../edge/evcs/ocpp/server/EvcsOcppServer.java | 27 +++++++++++++++++--
 .../edge/evcs/ocpp/server/MyJsonServer.java   |  3 ++-
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/EvcsOcppServer.java b/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/EvcsOcppServer.java
index cabfb8d05..8865f4c14 100644
--- a/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/EvcsOcppServer.java
+++ b/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/EvcsOcppServer.java
@@ -7,7 +7,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.UUID;
+
 import java.util.concurrent.CompletionStage;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.annotations.Activate;
@@ -51,11 +56,18 @@ public class EvcsOcppServer extends AbstractOpenemsComponent implements OpenemsC
 
 	public static final String DEFAULT_IP = "0.0.0.0";
 	public static final int DEFAULT_PORT = 8887;
+	/**
+	 * Delay in minutes before the JSON server is activated. This is a
+	 * workaround.
+	 */
+	public static final int MY_JSON_SERVER_DELAY_MINUTES = 3;
 
 	private final Logger log = LoggerFactory.getLogger(EvcsOcppServer.class);
 
 	/** The JSON server - responsible for the OCPP communication. */
 	private final MyJsonServer myJsonServer = new MyJsonServer(this);
+	private AtomicBoolean isMyJsonServerActivated = new AtomicBoolean(false);
+	private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
 	/** Currently connected sessions with their related evcs components. */
 	protected final Map<UUID, List<AbstractManagedOcppEvcsComponent>> activeEvcsSessions = new HashMap<>();
 
@@ -133,13 +145,24 @@ public class EvcsOcppServer extends AbstractOpenemsComponent implements OpenemsC
 		super.activate(context, config.id(), config.alias(), config.enabled());
 
 		this.config = config;
-		this.myJsonServer.activate(config.ip(), config.port());
+		this.executor.schedule(() -> {
+			try {
+				this.myJsonServer.activate(config.ip(), config.port());
+				this.isMyJsonServerActivated.set(true);
+			} catch (Exception e) {
+				this.logError(this.log, "Failed to activate MyJsonServer" + e.getClass() + ": " + e.getMessage());
+			}
+		}, MY_JSON_SERVER_DELAY_MINUTES, TimeUnit.MINUTES);
 	}
 
 	@Override
 	@Deactivate
 	protected void deactivate() {
-		this.myJsonServer.deactivate();
+		if (this.isMyJsonServerActivated.get()) {
+			this.myJsonServer.deactivate();
+			this.isMyJsonServerActivated.set(false);
+		}
+		this.executor.shutdown();
 		super.deactivate();
 	}
 
diff --git a/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/MyJsonServer.java b/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/MyJsonServer.java
index 66d4d78b3..8dd956a51 100644
--- a/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/MyJsonServer.java
+++ b/io.openems.edge.evcs.ocpp.server/src/io/openems/edge/evcs/ocpp/server/MyJsonServer.java
@@ -95,8 +95,9 @@ public class MyJsonServer {
 				var presentEvcss = MyJsonServer.this.parent.ocppEvcss.get(ocppIdentifier);
 
 				if (presentEvcss == null) {
-					return;
+					throw new RuntimeException("No EVCS found or not yet initialized for ocppId " + ocppIdentifier);
 				}
+
 				MyJsonServer.this.parent.activeEvcsSessions.put(sessionIndex, presentEvcss);
 
 				for (AbstractManagedOcppEvcsComponent evcs : presentEvcss) {
-- 
2.39.5 (Apple Git-154)

Screenshots

No response

Operating System

Ubuntu

How to reproduce the Error?

  1. Start the OpenEMS Edge.
  2. Send a request from the charge station before the component initialization is complete.
  3. Since the components are not initialized yet, the charge station fails to join properly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions