Coverage for /opt/conda/envs/apienv/lib/python3.10/site-packages/daiquiri/core/components/utils/monitor.py: 21%
29 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-14 02:13 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-11-14 02:13 +0000
1import logging
2import time
3from daiquiri.core.hardware.abstract import HardwareObject
4import gevent
6logger = logging.getLogger(__name__)
9def monitor(
10 object: HardwareObject, property: str, greenlet: gevent.greenlet, timeout=30
11):
12 """A monitor function to kill a greenlet if no update is recieved within a timeframe
14 This function can be used for example to monitor a running scan and kill the running
15 greenlet if a particular axis value has not changed within a certain timeframe.
17 Args:
18 object (HardwareObject): A daiquiri hardware object
19 property (str): The property on the object to monitor
20 greenlet (greenlet): The greenlet that should be killed
22 Kwargs:
23 timeout (int): An optional timeout, default 30s
25 """
26 last_update_time = time.time()
27 last_update_value = 0
29 running = True
31 def update_pos(obj, prop, value):
32 nonlocal last_update_time, last_update_value
33 if value != last_update_value:
34 last_update_value = value
35 last_update_time = time.time()
37 object.subscribe(property, update_pos)
39 def _monitor():
40 nonlocal last_update_time, running, greenlet
41 logger.info("Starting monitor")
42 while running:
43 last_update = round(time.time() - last_update_time, 2)
44 if last_update > timeout:
45 greenlet.kill()
46 raise RuntimeError(
47 f"Greenlet killed as monitor did not recieve an update on property `{property}` for object `{object.name()}` within timeout {timeout}s, last update {last_update}s ago"
48 )
50 time.sleep(5)
52 monitor_greenlet = gevent.spawn(_monitor)
54 def kill_monitor():
55 nonlocal monitor_greenlet, running
56 running = False
57 logger.info("Stopping monitor")
58 monitor_greenlet.kill()
59 object.unsubscribe(property, update_pos)
61 return monitor_greenlet, kill_monitor