SIENTIAPDE-1312
Update dependencies and enhance OpcRepository functionality - Updated sientia-dataops-library version to 1.4.7 in requirements files. - Modified GITHUB_BRANCH in values.yaml for improved pipeline management. - Refactored OpcRepository class to inherit from BaseActivity, adding enhanced logging and error handling during disconnection. - Implemented a disconnection fallback mechanism to ensure graceful handling of OPC server disconnections.
This commit is contained in:
@@ -10,14 +10,11 @@ with workflow.unsafe.imports_passed_through():
|
|||||||
from sientia_do.notifications.models import NotificationLevel
|
from sientia_do.notifications.models import NotificationLevel
|
||||||
from sientia_do.observability.logger import Logger
|
from sientia_do.observability.logger import Logger
|
||||||
from sientia_do.temporal.activities.postgres import Postgres
|
from sientia_do.temporal.activities.postgres import Postgres
|
||||||
from sientia_do.temporal.constants import now
|
from sientia_do.temporal.constants import now, DATETIME_FORMAT_FILENAME
|
||||||
|
|
||||||
from laborious.utils.repository.minio_repository import MinioRepository
|
from laborious.utils.repository.minio_repository import MinioRepository
|
||||||
|
|
||||||
|
|
||||||
DATETIME_FILENAME_FORMAT = '%Y-%m-%d_%H-%M-%S'
|
|
||||||
|
|
||||||
|
|
||||||
class Storage(Postgres):
|
class Storage(Postgres):
|
||||||
"""
|
"""
|
||||||
Extensions for Postgres activities with a helper to export query results
|
Extensions for Postgres activities with a helper to export query results
|
||||||
@@ -84,7 +81,7 @@ class Storage(Postgres):
|
|||||||
metadata = input_data.get('metadata', {})
|
metadata = input_data.get('metadata', {})
|
||||||
object_prefix = input_data.get('object_prefix', 'datasets/retrain')
|
object_prefix = input_data.get('object_prefix', 'datasets/retrain')
|
||||||
|
|
||||||
timestamp = now().strftime(DATETIME_FILENAME_FORMAT)
|
timestamp = now().strftime(DATETIME_FORMAT_FILENAME)
|
||||||
object_name = f'{object_prefix}_{timestamp}.parquet'
|
object_name = f'{object_prefix}_{timestamp}.parquet'
|
||||||
uri = f's3://{self.minio_repository.minio_bucket}/{object_name}'
|
uri = f's3://{self.minio_repository.minio_bucket}/{object_name}'
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import asyncio
|
||||||
|
import json
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -10,6 +12,7 @@ from asyncua.ua import DataValue, DateTime, Variant, VariantType
|
|||||||
from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler
|
from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler
|
||||||
from sientia_do.notifications.models import NotificationLevel
|
from sientia_do.notifications.models import NotificationLevel
|
||||||
from sientia_do.observability.logger import Logger
|
from sientia_do.observability.logger import Logger
|
||||||
|
from sientia_do.temporal.activities.base import BaseActivity
|
||||||
|
|
||||||
from laborious import metrics
|
from laborious import metrics
|
||||||
|
|
||||||
@@ -37,19 +40,19 @@ data_type_map = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class OpcRepository:
|
class OpcRepository(BaseActivity):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
opc_id: str,
|
opc_id: str,
|
||||||
url: str,
|
url: str,
|
||||||
|
pod_id: str,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
notification_handler: NotificationHandler,
|
notification_handler: NotificationHandler,
|
||||||
reconnection_interval: int = 60,
|
reconnection_interval: int = 60,
|
||||||
server_uri: str | None = None,
|
server_uri: str | None = None,
|
||||||
cert_path: str | None = None,
|
cert_path: str | None = None,
|
||||||
private_key_path: str | None = None,
|
private_key_path: str | None = None,
|
||||||
server_cert_path: str | None = None,
|
server_cert_path: str | None = None
|
||||||
pod_id: str | None = None,
|
|
||||||
):
|
):
|
||||||
self.url = url
|
self.url = url
|
||||||
self.id = opc_id
|
self.id = opc_id
|
||||||
@@ -65,6 +68,8 @@ class OpcRepository:
|
|||||||
self.client: None | Client = None
|
self.client: None | Client = None
|
||||||
self.pod_id = pod_id
|
self.pod_id = pod_id
|
||||||
|
|
||||||
|
BaseActivity.__init__(self, logger, notification_handler, set_error_counter=True)
|
||||||
|
|
||||||
self.metadata = {
|
self.metadata = {
|
||||||
'model_name': '-',
|
'model_name': '-',
|
||||||
'model_id': '-',
|
'model_id': '-',
|
||||||
@@ -125,7 +130,14 @@ class OpcRepository:
|
|||||||
Exception: If the connection to the OPC server fails.
|
Exception: If the connection to the OPC server fails.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.client = Client(self.url)
|
self.client = Client(self.url) # type: ignore[attr-defined]
|
||||||
|
|
||||||
|
self.client.name = self.pod_id
|
||||||
|
self.client.application_name = self.pod_id
|
||||||
|
pod_uri = self.pod_id.replace('-', ':')
|
||||||
|
self.client.application_uri = pod_uri
|
||||||
|
self.client.product_uri = pod_uri
|
||||||
|
|
||||||
if self.cert_path:
|
if self.cert_path:
|
||||||
await self.set_security()
|
await self.set_security()
|
||||||
self.logger.custom_info(f'Starting connection to OPC server {self.id}...', self.metadata)
|
self.logger.custom_info(f'Starting connection to OPC server {self.id}...', self.metadata)
|
||||||
@@ -169,6 +181,28 @@ class OpcRepository:
|
|||||||
'attachment_content': trace,
|
'attachment_content': trace,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 in attempt {i+1} of 5: {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):
|
||||||
"""
|
"""
|
||||||
Gracefully disconnect from the OPC server.
|
Gracefully disconnect from the OPC server.
|
||||||
@@ -179,11 +213,20 @@ class OpcRepository:
|
|||||||
"""
|
"""
|
||||||
if self.client is None:
|
if self.client is None:
|
||||||
return
|
return
|
||||||
try:
|
|
||||||
await self.client.disconnect()
|
errors = await self.disconnection_fallback()
|
||||||
self.logger.custom_info('Disconnected from OPC server', self.metadata)
|
if errors:
|
||||||
except Exception as e:
|
self.send_notification(
|
||||||
self.logger.custom_error(f'Failed to disconnect from OPC server: {e}', self.metadata)
|
metadata=self.metadata,
|
||||||
|
notification_id=f'OPC_DISCONNECTION_ERROR_{self.id}',
|
||||||
|
message=f'Failed to disconnect from OPC server in 5 attempts: {errors}',
|
||||||
|
block='opc_repository',
|
||||||
|
level=NotificationLevel.ERROR,
|
||||||
|
attachment_content=json.dumps(errors, indent=4),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.logger.warning(f'Disconnected from OPC server {self.id} successfully')
|
||||||
|
|
||||||
self.client = None
|
self.client = None
|
||||||
|
|
||||||
async def validate_connection(self) -> tuple[bool, dict[str, Any]]:
|
async def validate_connection(self) -> tuple[bool, dict[str, Any]]:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ psycopg2-binary
|
|||||||
sqlalchemy
|
sqlalchemy
|
||||||
asyncua
|
asyncua
|
||||||
redis
|
redis
|
||||||
git+ssh://git@github.com/Aignosi/sientia-dataops-library.git@1.4.6
|
git+ssh://git@github.com/Aignosi/sientia-dataops-library.git@1.4.7
|
||||||
prometheus-client
|
prometheus-client
|
||||||
botocore
|
botocore
|
||||||
boto3
|
boto3
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ psycopg2-binary
|
|||||||
sqlalchemy
|
sqlalchemy
|
||||||
asyncua
|
asyncua
|
||||||
redis
|
redis
|
||||||
git+ssh://git@github.com/Aignosi/sientia-dataops-library.git@1.4.6
|
git+ssh://git@github.com/Aignosi/sientia-dataops-library.git@1.4.7
|
||||||
git+ssh://git@github.com/Aignosi/sientia-mlops-library.git@0.39.0
|
git+ssh://git@github.com/Aignosi/sientia-mlops-library.git@0.39.0
|
||||||
prometheus-client
|
prometheus-client
|
||||||
botocore
|
botocore
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ env:
|
|||||||
- name: GITHUB_REPO_URL
|
- name: GITHUB_REPO_URL
|
||||||
value: "git@github.com:Aignosi/sientia-dataops-laborious_temporal.git"
|
value: "git@github.com:Aignosi/sientia-dataops-laborious_temporal.git"
|
||||||
- name: GITHUB_BRANCH
|
- name: GITHUB_BRANCH
|
||||||
value: SIENTIAPDE-1231-ajustar-o-retreino-do-courier-no-laborious
|
value: "SIENTIAPDE-1312-melhorias-e-correcoes-nas-pipelines-de-dados"
|
||||||
- name: PYTHON_APP
|
- name: PYTHON_APP
|
||||||
value: "laborious.worker.worker"
|
value: "laborious.worker.worker"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user