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);
+ }
+ }
)
);