You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by hu...@apache.org on 2020/11/26 12:35:37 UTC

[plc4x] branch update/opcua-server updated: Add Backoff handling, improved error repoting.

This is an automated email from the ASF dual-hosted git repository.

hutcheb pushed a commit to branch update/opcua-server
in repository https://gitbox.apache.org/repos/asf/plc4x.git


The following commit(s) were added to refs/heads/update/opcua-server by this push:
     new 97bf8c4  Add Backoff handling, improved error repoting.
97bf8c4 is described below

commit 97bf8c46292b6db15329f9d25cef187350c8ee3d
Author: hutcheb <be...@gmail.com>
AuthorDate: Thu Nov 26 07:35:23 2020 -0500

    Add Backoff handling, improved error repoting.
    
    - now reports BAD when connection to PLC is lost
    - Currently working on issue when device is disconnected and
    reconnected. GetConnection returns a non connected connection.
---
 .../java/opcuaserver/AttributeLoggingFilter.java   |  4 +-
 .../opcuaserver/backend/Plc4xCommunication.java    | 79 +++++++++++++++++-----
 .../java/opcuaserver/backend/Plc4xNamespace.java   | 11 ++-
 3 files changed, 72 insertions(+), 22 deletions(-)

diff --git a/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/AttributeLoggingFilter.java b/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/AttributeLoggingFilter.java
index 41ad5ef..b8eff3e 100644
--- a/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/AttributeLoggingFilter.java
+++ b/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/AttributeLoggingFilter.java
@@ -48,7 +48,7 @@ public class AttributeLoggingFilter implements AttributeFilter {
 
         // only log external reads
         if (attributePredicate.test(attributeId) && ctx.getSession().isPresent()) {
-            logger.info(
+            logger.debug(
                 "get nodeId={} attributeId={} value={}",
                 ctx.getNode().getNodeId(), attributeId, value
             );
@@ -61,7 +61,7 @@ public class AttributeLoggingFilter implements AttributeFilter {
     public void setAttribute(SetAttributeContext ctx, AttributeId attributeId, Object value) {
         // only log external writes
         if (attributePredicate.test(attributeId) && ctx.getSession().isPresent()) {
-            logger.info(
+            logger.debug(
                 "set nodeId={} attributeId={} value={}",
                 ctx.getNode().getNodeId(), attributeId, value
             );
diff --git a/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java b/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java
index 4f00ccd..f7d6664 100644
--- a/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java
+++ b/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xCommunication.java
@@ -95,6 +95,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.Map;
 import java.util.HashMap;
 
+import java.math.BigInteger;
 
 import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.ubyte;
 import static org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.Unsigned.uint;
@@ -105,6 +106,10 @@ public class Plc4xCommunication {
 
     private PlcDriverManager driverManager;
     private final Logger logger = LoggerFactory.getLogger(getClass());
+    private final Integer DEFAULT_TIMEOUT = 1000000;
+    private final Integer DEFAULT_RETRY_BACKOFF = 5000;
+
+    private Map<String, Long> failedConnectionList = new HashMap<>();
 
     Map<NodeId, DataItem> monitoredList = new HashMap<>();
 
@@ -117,12 +122,12 @@ public class Plc4xCommunication {
     }
 
     public void addField(DataItem item) {
-        logger.info("Adding item to monitored list " + item.getReadValueId());
+        logger.info("Adding item to OPC UA monitored list " + item.getReadValueId());
         monitoredList.put(item.getReadValueId().getNodeId(), item);
     }
 
     public void removeField(DataItem item) {
-        logger.info("Removing item from monitored list " + item.getReadValueId());
+        logger.info("Removing item from OPC UA monitored list " + item.getReadValueId());
         monitoredList.remove(item.getReadValueId().getNodeId());
     }
 
@@ -190,14 +195,43 @@ public class Plc4xCommunication {
 
     public Variant getValue(AttributeFilterContext.GetAttributeContext ctx, String tag, String connectionString) {
         PlcConnection connection = null;
+        Variant resp = null;
+
+        //Check if we just polled the connection and it failed. Wait for the backoff counter to expire before we try again.
+        if (failedConnectionList.containsKey(connectionString)) {
+            if (System.currentTimeMillis() > failedConnectionList.get(connectionString) + DEFAULT_RETRY_BACKOFF) {
+                failedConnectionList.remove(connectionString);
+            } else {
+                logger.debug("Waiting for back off timer - " + ((failedConnectionList.get(connectionString) + DEFAULT_RETRY_BACKOFF) - System.currentTimeMillis()) + " ms left");
+                return resp;
+            }
+        }
+
         try {
-          connection = driverManager.getConnection(connectionString);
+            connection = driverManager.getConnection(connectionString);
+            if (connection.isConnected() == false) {
+                logger.error("Get Connection returned a connection that isn't connected");
+                try {
+                  connection.close();
+                } catch (Exception e) {
+                  failedConnectionList.put(connectionString, System.currentTimeMillis());
+                  logger.warn("Close Failed" + e);
+                }
+                return resp;
+            }
+            logger.debug(connectionString + " Connected");
         } catch (PlcConnectionException e) {
-          logger.warn("Failed" + e);
+            logger.error("Failed to connect to device, error raised - " + e);
+            failedConnectionList.put(connectionString, System.currentTimeMillis());
+            return resp;
         }
-        logger.info(ctx.getNode().getNodeId().toString());
 
-        long timeout = 1000000;
+        if (!connection.getMetadata().canRead()) {
+            logger.error("This connection doesn't support reading.");
+            return resp;
+        }
+
+        long timeout = DEFAULT_TIMEOUT;
         if (monitoredList.containsKey(ctx.getNode().getNodeId())) {
             timeout = (long) monitoredList.get(ctx.getNode().getNodeId()).getSamplingInterval()*1000;
         }
@@ -210,35 +244,44 @@ public class Plc4xCommunication {
 
         PlcReadResponse response = null;
         try {
-          response = readRequest.execute().get(timeout, TimeUnit.MICROSECONDS);
-      } catch (InterruptedException | ExecutionException | TimeoutException e) {
-          logger.warn("Failed" + e);
-          try {
-            connection.close();
-        } catch (Exception exception) {
-            logger.warn("Close Failed" + exception);
-          }
+            response = readRequest.execute().get(timeout, TimeUnit.MICROSECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            logger.warn(e + " Occurred while reading value, using timeout of " + timeout);
+            try {
+                connection.close();
+            } catch (Exception exception) {
+                logger.warn("Closing Connection Failed with error - " + exception);
+            }
+            return resp;
         }
 
-        Variant resp = null;
-
         for (String fieldName : response.getFieldNames()) {
           if(response.getResponseCode(fieldName) == PlcResponseCode.OK) {
               int numValues = response.getNumberOfValues(fieldName);
               if(numValues == 1) {
-                  resp = new Variant(response.getObject(fieldName));
+                  if (response.getObject(fieldName) instanceof BigInteger) {
+                      resp = new Variant(ulong((BigInteger) response.getObject(fieldName)));
+                  } else {
+                      resp = new Variant(response.getObject(fieldName));
+                  }
               } else {
                 Object array = Array.newInstance(response.getObject(fieldName, 0).getClass(), numValues);
                 for (int i = 0; i < numValues; i++) {
-                    Array.set(array, i, response.getObject(fieldName, i));
+                    if (response.getObject(fieldName, i) instanceof BigInteger) {
+                        Array.set(array, i, ulong((BigInteger) response.getObject(fieldName, i)));
+                    } else {
+                        Array.set(array, i, response.getObject(fieldName, i));
+                    }
                 }
                 resp = new Variant(array);
               }
           }
         }
+
         try {
           connection.close();
         } catch (Exception e) {
+          failedConnectionList.put(connectionString, System.currentTimeMillis());
           logger.warn("Close Failed" + e);
         }
         return resp;
diff --git a/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xNamespace.java b/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xNamespace.java
index 31fc5cc..bdefffc 100644
--- a/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xNamespace.java
+++ b/sandbox/opcua-server/src/main/java/org/apache/plc4x/java/opcuaserver/backend/Plc4xNamespace.java
@@ -60,6 +60,7 @@ import org.eclipse.milo.opcua.stack.core.types.builtin.ExtensionObject;
 import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
 import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
 import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName;
+import org.eclipse.milo.opcua.stack.core.types.builtin.StatusCode;
 import org.eclipse.milo.opcua.stack.core.types.builtin.Variant;
 import org.eclipse.milo.opcua.stack.core.types.builtin.XmlElement;
 import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
@@ -205,8 +206,14 @@ public class Plc4xNamespace extends ManagedNamespaceWithLifecycle {
                 node.getFilterChain().addLast(
                     filter,
                     AttributeFilters.getValue(
-                        ctx ->
-                            new DataValue(plc4xServer.getValue(ctx, tag, connectionString))
+                        ctx -> {
+                            Variant retValue = plc4xServer.getValue(ctx, tag, connectionString);
+                            if (retValue == null) {
+                                return new DataValue(new Variant(null), StatusCode.BAD);
+                            } else {
+                                return new DataValue(retValue, StatusCode.GOOD);
+                            }
+                        }
                     )
                 );