SIENTIAPDE-1312
SIENTIAPDE-1318 Enhance OpcManager disconnection handling - Introduced a disconnection_fallback method to attempt multiple disconnects from the OPC UA server, improving reliability. - Updated error handling during connection attempts to ensure proper logging and notification of disconnection failures. - Refactored disconnect method to utilize the new fallback mechanism and maintain metrics accurately.
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import traceback
|
||||||
|
|
||||||
from asyncua import Client
|
from asyncua import Client
|
||||||
from asyncua.crypto.security_policies import SecurityPolicyBasic256
|
from asyncua.crypto.security_policies import SecurityPolicyBasic256
|
||||||
@@ -208,9 +210,8 @@ class OpcManager(BaseActivity):
|
|||||||
).set(1)
|
).set(1)
|
||||||
self.logger.info(f'Connection to {self.name} successful.')
|
self.logger.info(f'Connection to {self.name} successful.')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if self.client:
|
|
||||||
try:
|
try:
|
||||||
await self.client.disconnect()
|
await self.disconnect()
|
||||||
except Exception as internal_e:
|
except Exception as internal_e:
|
||||||
self.logger.error(f'And error occurred while creating connection from {self.name}, and an exception occurred while disconnecting: {internal_e}')
|
self.logger.error(f'And error occurred while creating connection from {self.name}, and an exception occurred while disconnecting: {internal_e}')
|
||||||
|
|
||||||
@@ -333,6 +334,28 @@ class OpcManager(BaseActivity):
|
|||||||
del self.subscriptions[subscription]
|
del self.subscriptions[subscription]
|
||||||
self.logger.info(f'Unsubscribed from {subscription}.')
|
self.logger.info(f'Unsubscribed from {subscription}.')
|
||||||
|
|
||||||
|
async def disconnection_fallback(self) -> list:
|
||||||
|
"""
|
||||||
|
Tries 5 times to disconnect from the OPC UA server, with a delay of 100ms x try.
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert self.client is not None
|
||||||
|
error_stack = []
|
||||||
|
for i in range(5):
|
||||||
|
try:
|
||||||
|
self.logger.info(f'Disconnecting from OPC UA server, attempt {i+1} of 5')
|
||||||
|
await self.client.disconnect()
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f'Failed to disconnect from OPC UA server: {e}')
|
||||||
|
error_stack.append({
|
||||||
|
'attempt': i+1,
|
||||||
|
'error': str(e),
|
||||||
|
'traceback': traceback.format_exc(),
|
||||||
|
})
|
||||||
|
await asyncio.sleep(0.1 * i)
|
||||||
|
return error_stack
|
||||||
|
|
||||||
async def disconnect(self):
|
async def disconnect(self):
|
||||||
"""
|
"""
|
||||||
Disconnects from the OPC UA server.
|
Disconnects from the OPC UA server.
|
||||||
@@ -363,20 +386,27 @@ class OpcManager(BaseActivity):
|
|||||||
except Exception as sub_error:
|
except Exception as sub_error:
|
||||||
self.logger.error(f'Failed to clean up subscription: {sub_error}')
|
self.logger.error(f'Failed to clean up subscription: {sub_error}')
|
||||||
|
|
||||||
# Inserir backoff para disconnect, emitindo métrica e alerta
|
|
||||||
try:
|
|
||||||
await self.client.disconnect()
|
|
||||||
except Exception as conn_error:
|
|
||||||
self.logger.error(f'Failed to disconnect from OPC UA server: {conn_error}')
|
|
||||||
|
|
||||||
finally:
|
errors = self.disconnection_fallback()
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
self.send_notification(
|
||||||
|
metadata=self.metadata,
|
||||||
|
notification_id=f'OPC_DISCONNECTION_ERROR_{self.name}',
|
||||||
|
message=f'Failed to disconnect from OPC UA server {self.name} after 5 attempts',
|
||||||
|
block='opc_manager',
|
||||||
|
level=NotificationLevel.ERROR,
|
||||||
|
attachment_content=json.dumps(errors, indent=4),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.logger.warning('Disconnected from OPC UA server.')
|
||||||
|
|
||||||
del self.client
|
del self.client
|
||||||
self.client = None
|
self.client = None
|
||||||
metrics.OPC_CONNECTION_STATUS.labels(
|
metrics.OPC_CONNECTION_STATUS.labels(
|
||||||
pod_id=self.pod_id, server_name=self.name, server_url=self.url
|
pod_id=self.pod_id, server_name=self.name, server_url=self.url
|
||||||
).set(0)
|
).set(0)
|
||||||
metrics.OPC_TAGS_SUBSCRIBED.labels(pod_id=self.pod_id, server_name=self.name).set(0)
|
metrics.OPC_TAGS_SUBSCRIBED.labels(pod_id=self.pod_id, server_name=self.name).set(0)
|
||||||
self.logger.warning('Disconnected from OPC UA server.')
|
|
||||||
|
|
||||||
async def datachange_notification(self, node, _val, data):
|
async def datachange_notification(self, node, _val, data):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user