Merge pull request #25 from Aignosi/fix/hotfix-opc-connection-optimizing
Refactor OPC server integrity checks to be asynchronous
This commit is contained in:
@@ -414,7 +414,7 @@ class Ingestor:
|
|||||||
|
|
||||||
# Check OPC cycles
|
# Check OPC cycles
|
||||||
self.logger.info('Checking OPC servers integrity...')
|
self.logger.info('Checking OPC servers integrity...')
|
||||||
self.ingestor_manager.check_opc_servers_integrity()
|
await self.ingestor_manager.check_opc_servers_integrity()
|
||||||
|
|
||||||
self.logger.info('Updating managed tags...')
|
self.logger.info('Updating managed tags...')
|
||||||
await self.update_ingestor_manager(current_managed_tags)
|
await self.update_ingestor_manager(current_managed_tags)
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ class IngestorManager(BaseActivity):
|
|||||||
def __del__(self):
|
def __del__(self):
|
||||||
asyncio.run(self.shutdown())
|
asyncio.run(self.shutdown())
|
||||||
|
|
||||||
async def update_opc_servers(self):
|
async def update_opc_servers(self): # NOSONAR
|
||||||
"""
|
"""
|
||||||
Updates the OPC (OLE for Process Control) server connections managed by the ingestor.
|
Updates the OPC (OLE for Process Control) server connections managed by the ingestor.
|
||||||
This method ensures that the OPC servers defined in `self.managed_tags` are properly
|
This method ensures that the OPC servers defined in `self.managed_tags` are properly
|
||||||
@@ -228,7 +228,7 @@ class IngestorManager(BaseActivity):
|
|||||||
|
|
||||||
elif server_instance.config != server_config:
|
elif server_instance.config != server_config:
|
||||||
self.logger.warning(f'Reinitializing OPC manager for server {server}')
|
self.logger.warning(f'Reinitializing OPC manager for server {server}')
|
||||||
server_instance.disconnect()
|
await server_instance.shutdown()
|
||||||
del self.opc_managers[server]
|
del self.opc_managers[server]
|
||||||
server_instance = await self.initialize_opc_from_config(server_config)
|
server_instance = await self.initialize_opc_from_config(server_config)
|
||||||
else:
|
else:
|
||||||
@@ -243,10 +243,12 @@ class IngestorManager(BaseActivity):
|
|||||||
f'Failed to initialize OPC manager for server {server}, '
|
f'Failed to initialize OPC manager for server {server}, '
|
||||||
f'removing server from managed tags.'
|
f'removing server from managed tags.'
|
||||||
)
|
)
|
||||||
_a = [
|
|
||||||
|
for slot, _value in current_managed_tags.items():
|
||||||
|
if server in self.opc_managers:
|
||||||
|
await self.opc_managers[server].shutdown()
|
||||||
|
del self.opc_managers[server]
|
||||||
self.managed_tags[slot].pop(server, None)
|
self.managed_tags[slot].pop(server, None)
|
||||||
for slot, _value in current_managed_tags.items()
|
|
||||||
]
|
|
||||||
|
|
||||||
servers = list(self.opc_managers.keys())
|
servers = list(self.opc_managers.keys())
|
||||||
for server in servers:
|
for server in servers:
|
||||||
@@ -254,12 +256,12 @@ class IngestorManager(BaseActivity):
|
|||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
f'Server {server} not found in managed tags. Desconnecting from server.'
|
f'Server {server} not found in managed tags. Desconnecting from server.'
|
||||||
)
|
)
|
||||||
await self.opc_managers[server].disconnect()
|
await self.opc_managers[server].shutdown()
|
||||||
self.opc_managers.pop(server, None)
|
self.opc_managers.pop(server, None)
|
||||||
|
|
||||||
metrics.OPC_MANAGERS_ACTIVE.labels(pod_id=self.pod_id).set(len(self.opc_managers))
|
metrics.OPC_MANAGERS_ACTIVE.labels(pod_id=self.pod_id).set(len(self.opc_managers))
|
||||||
|
|
||||||
def check_opc_servers_integrity(self):
|
async def check_opc_servers_integrity(self):
|
||||||
"""
|
"""
|
||||||
Checks the integrity of the OPC servers and updates the OPC servers if necessary.
|
Checks the integrity of the OPC servers and updates the OPC servers if necessary.
|
||||||
|
|
||||||
@@ -282,6 +284,9 @@ class IngestorManager(BaseActivity):
|
|||||||
self.logger.warning(f'OPC server {server} is lost. Server will be disconnected.')
|
self.logger.warning(f'OPC server {server} is lost. Server will be disconnected.')
|
||||||
|
|
||||||
for slot, _config in self.managed_tags.items():
|
for slot, _config in self.managed_tags.items():
|
||||||
|
if server in self.opc_managers:
|
||||||
|
await self.opc_managers[server].shutdown()
|
||||||
|
del self.opc_managers[server]
|
||||||
self.managed_tags[slot].pop(server, None)
|
self.managed_tags[slot].pop(server, None)
|
||||||
|
|
||||||
metrics.OPC_MANAGERS_ACTIVE.labels(pod_id=self.pod_id).set(len(self.opc_managers))
|
metrics.OPC_MANAGERS_ACTIVE.labels(pod_id=self.pod_id).set(len(self.opc_managers))
|
||||||
@@ -604,4 +609,7 @@ class IngestorManager(BaseActivity):
|
|||||||
to_remove.append([slot, server])
|
to_remove.append([slot, server])
|
||||||
|
|
||||||
for slot, server in to_remove:
|
for slot, server in to_remove:
|
||||||
|
if server in self.opc_managers:
|
||||||
|
await self.opc_managers[server].shutdown()
|
||||||
|
del self.opc_managers[server]
|
||||||
self.managed_tags[slot].pop(server, None)
|
self.managed_tags[slot].pop(server, None)
|
||||||
|
|||||||
@@ -107,6 +107,9 @@ class OpcManager(BaseActivity):
|
|||||||
f'nodes={self.nodes}, subscriptions={self.subscriptions}'
|
f'nodes={self.nodes}, subscriptions={self.subscriptions}'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
asyncio.run(self.shutdown())
|
||||||
|
|
||||||
async def shutdown(self):
|
async def shutdown(self):
|
||||||
"""
|
"""
|
||||||
Comprehensive cleanup method for graceful shutdown.
|
Comprehensive cleanup method for graceful shutdown.
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ async def test_update_opc_servers(metrics, opc_manager, ingestor_manager):
|
|||||||
'slot2': {'server3': {'config': 'config3'}, 'server1': {'config': 'config1'}},
|
'slot2': {'server3': {'config': 'config3'}, 'server1': {'config': 'config1'}},
|
||||||
}
|
}
|
||||||
|
|
||||||
mock = MagicMock(config={'config': 'old_config2'})
|
mock = AsyncMock(config={'config': 'old_config2'})
|
||||||
ingestor_manager.opc_managers['server3'] = AsyncMock(config={'config': 'config3'})
|
ingestor_manager.opc_managers['server3'] = AsyncMock(config={'config': 'config3'})
|
||||||
ingestor_manager.opc_managers['server2'] = mock
|
ingestor_manager.opc_managers['server2'] = mock
|
||||||
ingestor_manager.opc_managers['server4'] = AsyncMock()
|
ingestor_manager.opc_managers['server4'] = AsyncMock()
|
||||||
@@ -472,8 +472,9 @@ async def test_subscribe_to_tags(ingestor_manager):
|
|||||||
ingestor_manager.managed_tags['slot1'].pop.assert_called_once_with('server3', None)
|
ingestor_manager.managed_tags['slot1'].pop.assert_called_once_with('server3', None)
|
||||||
|
|
||||||
|
|
||||||
|
@mark.asyncio
|
||||||
@patch('ingestor.managers.ingestor_manager.metrics')
|
@patch('ingestor.managers.ingestor_manager.metrics')
|
||||||
def test_check_opc_servers_integrity_all_healthy(metrics, ingestor_manager):
|
async def test_check_opc_servers_integrity_all_healthy(metrics, ingestor_manager):
|
||||||
# Setup mock OPC managers
|
# Setup mock OPC managers
|
||||||
opc_manager1 = MagicMock()
|
opc_manager1 = MagicMock()
|
||||||
opc_manager1.check_cycles.return_value = None
|
opc_manager1.check_cycles.return_value = None
|
||||||
@@ -491,7 +492,7 @@ def test_check_opc_servers_integrity_all_healthy(metrics, ingestor_manager):
|
|||||||
ingestor_manager.initialize_opc_from_config = MagicMock()
|
ingestor_manager.initialize_opc_from_config = MagicMock()
|
||||||
|
|
||||||
# Call the method
|
# Call the method
|
||||||
ingestor_manager.check_opc_servers_integrity()
|
await ingestor_manager.check_opc_servers_integrity()
|
||||||
|
|
||||||
# Verify that check_cycles and check_opc_listenning were called for each server
|
# Verify that check_cycles and check_opc_listenning were called for each server
|
||||||
opc_manager1.check_cycles.assert_called_once()
|
opc_manager1.check_cycles.assert_called_once()
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ async def test_loop(ingestor_manager_started):
|
|||||||
ingestor_manager_started.manage_no_slots = MagicMock()
|
ingestor_manager_started.manage_no_slots = MagicMock()
|
||||||
ingestor_manager_started.manage_leases = AsyncMock()
|
ingestor_manager_started.manage_leases = AsyncMock()
|
||||||
ingestor_manager_started.update_ingestor_manager = AsyncMock()
|
ingestor_manager_started.update_ingestor_manager = AsyncMock()
|
||||||
|
ingestor_manager_started.ingestor_manager.check_opc_servers_integrity = AsyncMock()
|
||||||
ingestor_manager_started.ingestor_manager.managed_tags = {
|
ingestor_manager_started.ingestor_manager.managed_tags = {
|
||||||
'slot1': 'server1',
|
'slot1': 'server1',
|
||||||
'slot2': 'server2',
|
'slot2': 'server2',
|
||||||
@@ -262,12 +263,16 @@ async def test_loop(ingestor_manager_started):
|
|||||||
ingestor_manager_started.manage_leases.assert_called_once_with(4, 3, 2)
|
ingestor_manager_started.manage_leases.assert_called_once_with(4, 3, 2)
|
||||||
ingestor_manager_started.ingestor_manager.update_slot_config.assert_called_once()
|
ingestor_manager_started.ingestor_manager.update_slot_config.assert_called_once()
|
||||||
|
|
||||||
|
ingestor_manager_started.ingestor_manager.check_opc_servers_integrity.assert_called_once()
|
||||||
|
ingestor_manager_started.update_ingestor_manager.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
@mark.asyncio
|
@mark.asyncio
|
||||||
async def test_loop_no_managed(ingestor_manager_started):
|
async def test_loop_no_managed(ingestor_manager_started):
|
||||||
ingestor_manager_started.manage_no_slots = MagicMock()
|
ingestor_manager_started.manage_no_slots = MagicMock()
|
||||||
ingestor_manager_started.manage_leases = AsyncMock()
|
ingestor_manager_started.manage_leases = AsyncMock()
|
||||||
ingestor_manager_started.update_ingestor_manager = AsyncMock()
|
ingestor_manager_started.update_ingestor_manager = AsyncMock()
|
||||||
|
ingestor_manager_started.ingestor_manager.check_opc_servers_integrity = AsyncMock()
|
||||||
ingestor_manager_started.ingestor_manager.managed_tags = {}
|
ingestor_manager_started.ingestor_manager.managed_tags = {}
|
||||||
ingestor_manager_started.ingestor_manager.get_active_ingestors = MagicMock(
|
ingestor_manager_started.ingestor_manager.get_active_ingestors = MagicMock(
|
||||||
return_value=['ingestor1', 'ingestor2']
|
return_value=['ingestor1', 'ingestor2']
|
||||||
@@ -288,6 +293,9 @@ async def test_loop_no_managed(ingestor_manager_started):
|
|||||||
ingestor_manager_started.ingestor_manager.update_slot_config.assert_called_once()
|
ingestor_manager_started.ingestor_manager.update_slot_config.assert_called_once()
|
||||||
ingestor_manager_started.logger.info.assert_any_call('No slots acquired in this loop')
|
ingestor_manager_started.logger.info.assert_any_call('No slots acquired in this loop')
|
||||||
|
|
||||||
|
ingestor_manager_started.ingestor_manager.check_opc_servers_integrity.assert_called_once()
|
||||||
|
ingestor_manager_started.update_ingestor_manager.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
@mark.asyncio
|
@mark.asyncio
|
||||||
async def test_loop_no_ingestor_manager(ingestor_manager_started):
|
async def test_loop_no_ingestor_manager(ingestor_manager_started):
|
||||||
|
|||||||
Reference in New Issue
Block a user