feat(burst-detection): update scada analysis flow
Server CI/CD / docker-image (push) Successful in 24s
Server CI/CD / deploy-fallback-log (push) Has been cancelled

This commit is contained in:
2026-07-17 16:31:46 +08:00
parent b4ecfbb87a
commit db6032bd84
5 changed files with 586 additions and 29 deletions
@@ -169,6 +169,38 @@ class InternalQueries:
else:
raise
@staticmethod
def query_latest_scada_time(
device_ids: List[str],
before_time: str | datetime | None = None,
db_name: str = None,
max_retries: int = 3,
) -> datetime | None:
"""Return the latest SCADA timestamp for the selected devices."""
before_dt = (
parse_utc_time(before_time, field_name="before_time")
if before_time is not None
else None
)
for attempt in range(max_retries):
try:
conn_string = (
get_timescaledb_pgconn_string(db_name=db_name)
if db_name
else get_timescaledb_pgconn_string()
)
with psycopg.Connection.connect(conn_string) as conn:
return ScadaRepository.get_latest_scada_time_sync(
conn,
device_ids,
before_dt,
)
except Exception:
if attempt < max_retries - 1:
time.sleep(1)
else:
raise
@staticmethod
def query_realtime_simulation_by_ids_timerange(
element_ids: List[str],
@@ -54,6 +54,27 @@ class ScadaRepository:
)
return cur.fetchall()
@staticmethod
def get_latest_scada_time_sync(
conn: Connection,
device_ids: List[str],
before_time: datetime | None = None,
) -> datetime | None:
with conn.cursor(row_factory=dict_row) as cur:
if before_time is None:
cur.execute(
"SELECT max(time) AS time FROM scada.scada_data WHERE device_id = ANY(%s)",
(device_ids,),
)
else:
cur.execute(
"SELECT max(time) AS time FROM scada.scada_data "
"WHERE device_id = ANY(%s) AND time <= %s",
(device_ids, before_time),
)
row = cur.fetchone()
return row["time"] if row else None
@staticmethod
async def get_scada_field_by_id_time_range(
conn: AsyncConnection,