annotate src/light9/background_loop.py @ 2405:69ca2b2fc133

overcomplicated attempt at persisting the pane layout in the rdf graph this was hard because we have to somehow wait for the graph to load before config'ing the panes
author drewp@bigasterisk.com
date Fri, 17 May 2024 16:58:26 -0700
parents 6f023afd6c16
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
2397
6f023afd6c16 dead code
drewp@bigasterisk.com
parents: 2393
diff changeset
1 # this is a fork of https://bigasterisk.com/code/background_loop/files/tip/
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
2 import asyncio
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
3 import logging
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
4 import time
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
5 import traceback
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
6 from typing import Any, Awaitable, Callable, Union
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
7
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
8 from prometheus_client import Gauge, Summary
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
9 from light9.recentfps import RecentFps
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
10 from braillegraph import horizontal_graph
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
11
2397
6f023afd6c16 dead code
drewp@bigasterisk.com
parents: 2393
diff changeset
12 log = logging.getLogger()
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
13
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
14 _created = []
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
15
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
16 # todo: some tricky typing
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
17 F_RET = Any
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
18 F_KWARGS = Any
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
19
2397
6f023afd6c16 dead code
drewp@bigasterisk.com
parents: 2393
diff changeset
20 UserAsyncFunc = Callable[
6f023afd6c16 dead code
drewp@bigasterisk.com
parents: 2393
diff changeset
21 ..., # always called with at least kwarg first_run=bool
6f023afd6c16 dead code
drewp@bigasterisk.com
parents: 2393
diff changeset
22 Awaitable[F_RET]]
6f023afd6c16 dead code
drewp@bigasterisk.com
parents: 2393
diff changeset
23 UserSyncFunc = Callable[
6f023afd6c16 dead code
drewp@bigasterisk.com
parents: 2393
diff changeset
24 ..., # see above
6f023afd6c16 dead code
drewp@bigasterisk.com
parents: 2393
diff changeset
25 F_RET]
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
26 UserFunc = Union[UserAsyncFunc, UserSyncFunc]
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
27
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
28
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
29 class Loop:
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
30
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
31 def __init__(
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
32 self,
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
33 func: UserFunc,
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
34 sleep_period: float,
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
35 metric_prefix: str,
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
36 extra_sleep_on_error: float = 2,
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
37 log_fps=False,
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
38 ):
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
39 self.func = func
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
40 self.sleep_period = sleep_period
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
41 self.extra_sleep_on_error = extra_sleep_on_error
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
42 self.metric_prefix = metric_prefix
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
43
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
44 self.up_metric = Gauge(f'{metric_prefix}_up', 'not erroring')
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
45 self.call_metric = Summary(f'{metric_prefix}_calls', 'calls')
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
46 self.lastSuccessRun = 0
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
47 self.everSucceeded = False
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
48 self.succeeding = False
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
49 self.fps = RecentFps() if log_fps else None
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
50 self.lastFpsLog = 0
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
51
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
52 async def call_func(self, first_run: bool, call_kwargs={}) -> F_RET:
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
53 with self.call_metric.time():
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
54 if asyncio.iscoroutinefunction(self.func):
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
55 ret = await self.func(first_run=first_run, **call_kwargs)
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
56 else:
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
57 ret = self.func(first_run=first_run, **call_kwargs)
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
58 return ret
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
59
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
60 async def _run(self):
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
61 self.first_run = True
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
62 self.newlyFailing = True
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
63 while True:
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
64 await self._runOne()
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
65 await asyncio.sleep(self.sleep_period)
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
66
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
67 async def runNow(self, **kwargs: F_KWARGS) -> F_RET:
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
68 """unlike background runs, you get to pass more args and get your func's
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
69 return value.
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
70 """
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
71 return await self._runOne(call_kwargs=kwargs)
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
72
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
73 async def _runOne(self, call_kwargs={}):
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
74 now = time.time()
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
75 self._updateFps(now)
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
76 try:
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
77 result = await self.call_func(self.first_run, call_kwargs)
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
78 self.lastSuccessRun = time.time()
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
79 if self.fps:
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
80 self.fps.mark()
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
81 self.up_metric.set(1)
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
82 self.everSucceeded = True
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
83 self.newlyFailing = True
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
84 self.first_run = False
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
85 except Exception as ex:
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
86 if self.newlyFailing:
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
87 traceback.print_exc()
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
88 self.newlyFailing = False
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
89 else:
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
90 log.error(ex)
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
91 self.up_metric.set(0)
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
92 result = None
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
93 self.succeeding = False
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
94
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
95 await asyncio.sleep(self.extra_sleep_on_error)
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
96 # todo: something that reveals error ratio
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
97 return result
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
98
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
99 def _updateFps(self, now: float):
2218
436a1fdbfe4a comment
drewp@bigasterisk.com
parents: 2216
diff changeset
100 # not sure i even want this- it's redundant with some metrics code
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
101 if self.fps is None:
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
102 return
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
103 if now < self.lastFpsLog + 5:
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
104 return
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
105 d = self.fps()
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
106 y_hi = 1 / self.sleep_period
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
107 if not d:
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
108 return
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
109 pts = [int(min(4, y / y_hi * 4)) for y in d['recents']]
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
110 log.info(f'{self.metric_prefix} fps={d["average"]:3.1f} (req={y_hi:3.1f}) {horizontal_graph(pts)}')
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
111 self.lastFpsLog = now
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
112
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
113
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
114 def loop_forever(
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
115 func: UserFunc,
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
116 sleep_period: float,
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
117 metric_prefix='background_loop',
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
118 up_metric=None,
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
119 call_metric=None,
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
120 extra_sleep_on_error=2,
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
121 log_fps=False,
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
122 ):
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
123 """
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
124 sleep_period is the sleep time after however long func takes to run
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
125 """
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
126 if up_metric is not None or call_metric is not None:
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
127 raise NotImplementedError('remove old-style metrics')
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
128
2216
acf1b68d031a fancier background_loop reporting for faders
drewp@bigasterisk.com
parents: 2215
diff changeset
129 loop = Loop(func, sleep_period, metric_prefix, extra_sleep_on_error, log_fps)
2215
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
130 _created.append(asyncio.create_task(loop._run()))
d8853f173568 fork background_loop
drewp@bigasterisk.com
parents:
diff changeset
131 return loop