From e68d7f5d0126da95d97ee3b268ad33e5a8957f64 Mon Sep 17 00:00:00 2001 From: David Perl Date: Fri, 10 Jul 2026 10:13:14 +0200 Subject: [PATCH] feat: cache status updates in background thread --- src/aare/daq/daq.py | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/aare/daq/daq.py b/src/aare/daq/daq.py index 2efb1ae7..3a942980 100644 --- a/src/aare/daq/daq.py +++ b/src/aare/daq/daq.py @@ -5,6 +5,7 @@ import time from datetime import datetime, timezone from math import ceil from pathlib import Path +from threading import RLock, Thread from typing import Callable, List, Optional, Tuple from aarecommon.config.beamline import cfg_get @@ -66,6 +67,7 @@ from aarecommon.models.raster_grid import CompletedRasterGrid, RasterGridRequest from aarecommon.models.rotation_scan import CompletedRotationScan, RotationScanRequest from aarecommon.models.tell import TellPhaseEnum, TellStateModel from aareDB import SampleEventType +from pyparsing.helpers import empty from aare.daq import workflows from aare.daq.aaredb import AareWrapper @@ -290,6 +292,10 @@ class AareDAQ: self._automation_last_sample_name = "" self._automation_samples_in_queue = 0 self._last_mount_error_message = "" + self._status_lock = RLock() + self._status_update_thread = Thread(target=self._status_update_loop, daemon=True) + self._status_update_error: Exception | None = None + self._status_update_thread.start() self._screenshot_service = ScreenshotService( mlbox=self.__mlbox, @@ -3398,8 +3404,8 @@ class AareDAQ: poni_rot2_rad=0.0, ) - @property - def status(self) -> DAQStatusModel: + def _update_status(self): + start = time.perf_counter() try: # og_start = time.perf_counter() safe_sample, tell_ok, tell_err = self._safe_sample() @@ -3424,7 +3430,7 @@ class AareDAQ: ) # logger.debug(f"Safe session status call took {time.perf_counter() - start:.3f}s") # start = time.perf_counter() - status = DAQStatusModel( + _cached_status = DAQStatusModel( state=self.state, busy=self.busy, geom=safe_geom, @@ -3444,14 +3450,38 @@ class AareDAQ: aerotech_connected=aerotech_ok, aerotech_error=aerotech_err, ) - # logger.debug(f"Creating DAQStatusModel took {time.perf_counter() - start:.3f}s") - # logger.debug(f"returning status call took {time.perf_counter() - og_start:.3f}s") - return status + with self._status_lock: + self._cached_status = _cached_status + # logger.debug(f"returning status call took {time.perf_counter() - og_start:.3f}s") except Exception as e: logger.error(f"Failed to retrieve DAQ status: {e}") raise + logger.debug(f"Updating status took {time.perf_counter() - start:.3f}s") + + def _status_update_loop(self): + while True: + try: + self._update_status() + except Exception as e: + self._status_update_error = e + return + time.sleep(0.1) + + @property + def status(self) -> DAQStatusModel: + if not self._status_update_thread.is_alive(): + self._status_update_thread.join(timeout=0.5) + if self._status_update_error is not None: + raise self._status_update_error + else: + raise RuntimeError( + "DAQ status update thread failed with an error not returned from the update thread" + ) + with self._status_lock: + return copy.deepcopy(self._cached_status) + def cancel(self): if self.__cfg.state == BeamlineStateEnum.DataCollection: self.__devs.aerotech.cancel()