Merge branch 'feature/SIENTIAPDE-1972-gateway-write-read' into feature/SIENTIAPDE-1972-gateway-wiring

This commit is contained in:
PedroHMCosme
2026-09-22 11:28:06 -03:00
8 changed files with 132 additions and 39 deletions

View File

@@ -40,7 +40,11 @@ class ActiveReadEngine(SientiaMonitoring):
)
async def read_now(
self, server_id: str, addr: str, names: list[dict] | None = None, server_cfg: dict | None = None
self,
server_id: str,
addr: str,
names: list[dict] | None = None,
server_cfg: dict | None = None,
) -> dict:
"""Read `addr` on `server_id` right now; persist via sink only if `names` given."""
tags = {'pod_id': self.pod_id, 'server_name': server_id}
@@ -72,7 +76,9 @@ class ActiveReadEngine(SientiaMonitoring):
source_str = self._format_ts(source_ts)
persisted = bool(names)
if persisted:
await self.sink.publish_reading(tag=addr, value=value, timestamp=source_str, names=names)
await self.sink.publish_reading(
tag=addr, value=value, timestamp=source_str, names=names
)
return {
'value': value,
'opc_status_code': status_name,
@@ -96,7 +102,9 @@ class ActiveReadEngine(SientiaMonitoring):
if source_ts is None:
return
lag = MonotonicClock.now_wall() - source_ts.replace(tzinfo=OPC_TIMEZONE).timestamp()
await self.emit_metric(metric_object=metrics.OPC_READ_LAG, method='set', value=lag, tags=tags)
await self.emit_metric(
metric_object=metrics.OPC_READ_LAG, method='set', value=lag, tags=tags
)
async def scheduled_tick(self, slot: dict) -> None:
"""Sweep every server/tag in a parsed slot, reading tags due for an active read."""

View File

@@ -37,13 +37,24 @@ _VARIANT_TYPES = {
# ponytail: same reconnect-worthy Bad*-status subset as laborious's
# opc_repository.py (different repo, not importable here); keep in sync by
# hand or promote to a shared lib if it drifts.
_SESSION_BAD_NAMES = frozenset({
'BadSessionIdInvalid', 'BadSessionClosed', 'BadSessionNotActivated',
'BadSecureChannelIdInvalid', 'BadSecureChannelClosed', 'BadSecureChannelTokenUnknown',
'BadTcpSecureChannelUnknown', 'BadServerNotConnected', 'BadConnectionClosed',
'BadConnectionRejected', 'BadNotConnected', 'BadTimeout', 'BadRequestTimeout',
'BadTooManySessions',
})
_SESSION_BAD_NAMES = frozenset(
{
'BadSessionIdInvalid',
'BadSessionClosed',
'BadSessionNotActivated',
'BadSecureChannelIdInvalid',
'BadSecureChannelClosed',
'BadSecureChannelTokenUnknown',
'BadTcpSecureChannelUnknown',
'BadServerNotConnected',
'BadConnectionClosed',
'BadConnectionRejected',
'BadNotConnected',
'BadTimeout',
'BadRequestTimeout',
'BadTooManySessions',
}
)
@dataclass
@@ -174,7 +185,11 @@ class WriteEngine(SientiaMonitoring):
metric_object=metrics.OPC_WRITE_STATUS_BY_MODEL,
method='set',
value=1,
tags={'pod_id': self.pod_id, 'model_id': cmd.get('model_id', 'unknown'), 'status': 'ok'},
tags={
'pod_id': self.pod_id,
'model_id': cmd.get('model_id', 'unknown'),
'status': 'ok',
},
)
result = WriteResult(ok=True, status='ok', opc_status_code='Good', message='')
await self.sink.update_write_status(cmd, result)

View File

@@ -57,7 +57,11 @@ class DataSink:
f'UPDATE {schema}.{table} SET write_status = :status ' # noqa: S608
'WHERE timestamp = :timestamp AND model_id = :model_id'
)
params = {'status': result.status, 'timestamp': cmd['timestamp'], 'model_id': cmd['model_id']}
params = {
'status': result.status,
'timestamp': cmd['timestamp'],
'model_id': cmd['model_id'],
}
# ponytail: sync engine call inside async def — same pattern sientia_do's own
# Postgres activities use (e.g. export_data_to_postgres); no async pg driver here.
with self.postgres.engine.begin() as connection:

View File

@@ -142,35 +142,49 @@ NOTIFICATIONS_SENT = Counter(
# --- Gateway: Write metrics ---
OPC_WRITE_TOTAL = Counter(
'opc_write_total', 'OPC active write attempts',
'opc_write_total',
'OPC active write attempts',
['pod_id', 'server_name', 'model_id', 'result'], # result: success|error
)
OPC_WRITE_LATENCY = Histogram(
'opc_write_latency_seconds', 'OPC active write latency', ['pod_id', 'server_name'],
'opc_write_latency_seconds',
'OPC active write latency',
['pod_id', 'server_name'],
)
OPC_WRITE_STATUS_BY_MODEL = Gauge(
'opc_write_status_by_model', 'Last write status per model (1=ok,0=error)',
'opc_write_status_by_model',
'Last write status per model (1=ok,0=error)',
['pod_id', 'model_id', 'status'],
)
# --- Gateway: Active read metrics ---
OPC_ACTIVE_READ_TOTAL = Counter(
'opc_active_read_total', 'OPC active read attempts',
'opc_active_read_total',
'OPC active read attempts',
['pod_id', 'server_name', 'result'],
)
OPC_ACTIVE_READ_LATENCY = Histogram(
'opc_active_read_latency_seconds', 'OPC active read latency', ['pod_id', 'server_name'],
'opc_active_read_latency_seconds',
'OPC active read latency',
['pod_id', 'server_name'],
)
OPC_READ_LAG = Gauge(
'opc_read_lag_seconds', 'Lag between OPC source timestamp and machine time',
'opc_read_lag_seconds',
'Lag between OPC source timestamp and machine time',
['pod_id', 'server_name'],
)
OPC_TAG_VALUE = Gauge(
'opc_tag_value', 'Last value read per tag/model', ['pod_id', 'tag_name', 'model_id'],
'opc_tag_value',
'Last value read per tag/model',
['pod_id', 'tag_name', 'model_id'],
)
# --- Gateway: connection/error metrics ---
OPC_DISCONNECTIONS_TOTAL = Counter(
'opc_disconnections_total', 'OPC disconnections', ['pod_id', 'server_name'],
'opc_disconnections_total',
'OPC disconnections',
['pod_id', 'server_name'],
)
OPC_ERROR_BY_TYPE = Counter(
'opc_error_by_type_total', 'OPC errors by type', ['pod_id', 'server_name', 'error_type'],
'opc_error_by_type_total',
'OPC errors by type',
['pod_id', 'server_name', 'error_type'],
)