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

1import logging 

2import time 

3from daiquiri.core.hardware.abstract import HardwareObject 

4import gevent 

5 

6logger = logging.getLogger(__name__) 

7 

8 

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 

13 

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. 

16 

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 

21 

22 Kwargs: 

23 timeout (int): An optional timeout, default 30s 

24 

25 """ 

26 last_update_time = time.time() 

27 last_update_value = 0 

28 

29 running = True 

30 

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() 

36 

37 object.subscribe(property, update_pos) 

38 

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 ) 

49 

50 time.sleep(5) 

51 

52 monitor_greenlet = gevent.spawn(_monitor) 

53 

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) 

60 

61 return monitor_greenlet, kill_monitor