ominfra 0.0.0.dev102__py3-none-any.whl → 0.0.0.dev104__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1410,7 +1410,7 @@ class DataclassObjMarshaler(ObjMarshaler):
1410
1410
  return {k: m.marshal(getattr(o, k)) for k, m in self.fs.items()}
1411
1411
 
1412
1412
  def unmarshal(self, o: ta.Any) -> ta.Any:
1413
- return self.ty(**{k: self.fs[k].unmarshal(v) for k, v in o.items() if self.nonstrict or k in self.fs})
1413
+ return self.ty(**{k: self.fs[k].unmarshal(v) for k, v in o.items() if not self.nonstrict or k in self.fs})
1414
1414
 
1415
1415
 
1416
1416
  @dc.dataclass(frozen=True)
@@ -1470,7 +1470,10 @@ class UuidObjMarshaler(ObjMarshaler):
1470
1470
  return uuid.UUID(o)
1471
1471
 
1472
1472
 
1473
- _OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = {
1473
+ ##
1474
+
1475
+
1476
+ _DEFAULT_OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = {
1474
1477
  **{t: NopObjMarshaler() for t in (type(None),)},
1475
1478
  **{t: CastObjMarshaler(t) for t in (int, float, str, bool)},
1476
1479
  **{t: Base64ObjMarshaler(t) for t in (bytes, bytearray)},
@@ -1499,20 +1502,19 @@ _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES: ta.Dict[ta.Any, type] = {
1499
1502
  }
1500
1503
 
1501
1504
 
1502
- def register_opj_marshaler(ty: ta.Any, m: ObjMarshaler) -> None:
1503
- if ty in _OBJ_MARSHALERS:
1504
- raise KeyError(ty)
1505
- _OBJ_MARSHALERS[ty] = m
1506
-
1507
-
1508
- def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
1505
+ def _make_obj_marshaler(
1506
+ ty: ta.Any,
1507
+ rec: ta.Callable[[ta.Any], ObjMarshaler],
1508
+ *,
1509
+ nonstrict_dataclasses: bool = False,
1510
+ ) -> ObjMarshaler:
1509
1511
  if isinstance(ty, type):
1510
1512
  if abc.ABC in ty.__bases__:
1511
1513
  impls = [ # type: ignore
1512
1514
  PolymorphicObjMarshaler.Impl(
1513
1515
  ity,
1514
1516
  ity.__qualname__,
1515
- get_obj_marshaler(ity),
1517
+ rec(ity),
1516
1518
  )
1517
1519
  for ity in deep_subclasses(ty)
1518
1520
  if abc.ABC not in ity.__bases__
@@ -1528,7 +1530,8 @@ def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
1528
1530
  if dc.is_dataclass(ty):
1529
1531
  return DataclassObjMarshaler(
1530
1532
  ty,
1531
- {f.name: get_obj_marshaler(f.type) for f in dc.fields(ty)},
1533
+ {f.name: rec(f.type) for f in dc.fields(ty)},
1534
+ nonstrict=nonstrict_dataclasses,
1532
1535
  )
1533
1536
 
1534
1537
  if is_generic_alias(ty):
@@ -1538,7 +1541,7 @@ def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
1538
1541
  pass
1539
1542
  else:
1540
1543
  k, v = ta.get_args(ty)
1541
- return MappingObjMarshaler(mt, get_obj_marshaler(k), get_obj_marshaler(v))
1544
+ return MappingObjMarshaler(mt, rec(k), rec(v))
1542
1545
 
1543
1546
  try:
1544
1547
  st = _OBJ_MARSHALER_GENERIC_ITERABLE_TYPES[ta.get_origin(ty)]
@@ -1546,33 +1549,71 @@ def _make_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
1546
1549
  pass
1547
1550
  else:
1548
1551
  [e] = ta.get_args(ty)
1549
- return IterableObjMarshaler(st, get_obj_marshaler(e))
1552
+ return IterableObjMarshaler(st, rec(e))
1550
1553
 
1551
1554
  if is_union_alias(ty):
1552
- return OptionalObjMarshaler(get_obj_marshaler(get_optional_alias_arg(ty)))
1555
+ return OptionalObjMarshaler(rec(get_optional_alias_arg(ty)))
1553
1556
 
1554
1557
  raise TypeError(ty)
1555
1558
 
1556
1559
 
1557
- def get_obj_marshaler(ty: ta.Any) -> ObjMarshaler:
1558
- try:
1559
- return _OBJ_MARSHALERS[ty]
1560
- except KeyError:
1561
- pass
1560
+ ##
1562
1561
 
1563
- p = ProxyObjMarshaler()
1564
- _OBJ_MARSHALERS[ty] = p
1565
- try:
1566
- m = _make_obj_marshaler(ty)
1567
- except Exception:
1568
- del _OBJ_MARSHALERS[ty]
1569
- raise
1570
- else:
1571
- p.m = m
1562
+
1563
+ _OBJ_MARSHALERS_LOCK = threading.RLock()
1564
+
1565
+ _OBJ_MARSHALERS: ta.Dict[ta.Any, ObjMarshaler] = dict(_DEFAULT_OBJ_MARSHALERS)
1566
+
1567
+ _OBJ_MARSHALER_PROXIES: ta.Dict[ta.Any, ProxyObjMarshaler] = {}
1568
+
1569
+
1570
+ def register_opj_marshaler(ty: ta.Any, m: ObjMarshaler) -> None:
1571
+ with _OBJ_MARSHALERS_LOCK:
1572
+ if ty in _OBJ_MARSHALERS:
1573
+ raise KeyError(ty)
1572
1574
  _OBJ_MARSHALERS[ty] = m
1575
+
1576
+
1577
+ def get_obj_marshaler(
1578
+ ty: ta.Any,
1579
+ *,
1580
+ no_cache: bool = False,
1581
+ **kwargs: ta.Any,
1582
+ ) -> ObjMarshaler:
1583
+ with _OBJ_MARSHALERS_LOCK:
1584
+ if not no_cache:
1585
+ try:
1586
+ return _OBJ_MARSHALERS[ty]
1587
+ except KeyError:
1588
+ pass
1589
+
1590
+ try:
1591
+ return _OBJ_MARSHALER_PROXIES[ty]
1592
+ except KeyError:
1593
+ pass
1594
+
1595
+ rec = functools.partial(
1596
+ get_obj_marshaler,
1597
+ no_cache=no_cache,
1598
+ **kwargs,
1599
+ )
1600
+
1601
+ p = ProxyObjMarshaler()
1602
+ _OBJ_MARSHALER_PROXIES[ty] = p
1603
+ try:
1604
+ m = _make_obj_marshaler(ty, rec, **kwargs)
1605
+ finally:
1606
+ del _OBJ_MARSHALER_PROXIES[ty]
1607
+ p.m = m
1608
+
1609
+ if not no_cache:
1610
+ _OBJ_MARSHALERS[ty] = m
1573
1611
  return m
1574
1612
 
1575
1613
 
1614
+ ##
1615
+
1616
+
1576
1617
  def marshal_obj(o: ta.Any, ty: ta.Any = None) -> ta.Any:
1577
1618
  return get_obj_marshaler(ty if ty is not None else type(o)).marshal(o)
1578
1619
 
@@ -0,0 +1,139 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ """
4
+ TODO:
5
+ - implement stop lol
6
+ - collective heartbeat monitoring - ThreadWorkerGroups
7
+ - group -> 'context'? :|
8
+ - shared stop_event?
9
+ """
10
+ import abc
11
+ import dataclasses as dc
12
+ import threading
13
+ import time
14
+ import typing as ta
15
+
16
+ from omlish.lite.contextmanagers import ExitStacked
17
+ from omlish.lite.logs import log
18
+
19
+
20
+ T = ta.TypeVar('T')
21
+ ThreadWorkerT = ta.TypeVar('ThreadWorkerT', bound='ThreadWorker')
22
+
23
+
24
+ ##
25
+
26
+
27
+ class ThreadWorker(ExitStacked, abc.ABC):
28
+ def __init__(
29
+ self,
30
+ *,
31
+ stop_event: ta.Optional[threading.Event] = None,
32
+ ) -> None:
33
+ super().__init__()
34
+
35
+ if stop_event is None:
36
+ stop_event = threading.Event()
37
+ self._stop_event = stop_event
38
+
39
+ self._lock = threading.RLock()
40
+ self._thread: ta.Optional[threading.Thread] = None
41
+ self._last_heartbeat: ta.Optional[float] = None
42
+
43
+ #
44
+
45
+ def __enter__(self: ThreadWorkerT) -> ThreadWorkerT:
46
+ with self._lock:
47
+ return super().__enter__() # noqa
48
+
49
+ #
50
+
51
+ def should_stop(self) -> bool:
52
+ return self._stop_event.is_set()
53
+
54
+ class Stopping(Exception): # noqa
55
+ pass
56
+
57
+ #
58
+
59
+ @property
60
+ def last_heartbeat(self) -> ta.Optional[float]:
61
+ return self._last_heartbeat
62
+
63
+ def _heartbeat(
64
+ self,
65
+ *,
66
+ no_stop_check: bool = False,
67
+ ) -> None:
68
+ self._last_heartbeat = time.time()
69
+
70
+ if not no_stop_check and self.should_stop():
71
+ log.info('Stopping: %s', self)
72
+ raise ThreadWorker.Stopping
73
+
74
+ #
75
+
76
+ def has_started(self) -> bool:
77
+ return self._thread is not None
78
+
79
+ def is_alive(self) -> bool:
80
+ return (thr := self._thread) is not None and thr.is_alive()
81
+
82
+ def start(self) -> None:
83
+ with self._lock:
84
+ if self._thread is not None:
85
+ raise RuntimeError('Thread already started: %r', self)
86
+
87
+ thr = threading.Thread(target=self.__run)
88
+ self._thread = thr
89
+ thr.start()
90
+
91
+ #
92
+
93
+ def __run(self) -> None:
94
+ try:
95
+ self._run()
96
+ except ThreadWorker.Stopping:
97
+ log.exception('Thread worker stopped: %r', self)
98
+ except Exception: # noqa
99
+ log.exception('Error in worker thread: %r', self)
100
+ raise
101
+
102
+ @abc.abstractmethod
103
+ def _run(self) -> None:
104
+ raise NotImplementedError
105
+
106
+ #
107
+
108
+ def stop(self) -> None:
109
+ self._stop_event.set()
110
+
111
+ def join(self, timeout: ta.Optional[float] = None) -> None:
112
+ with self._lock:
113
+ if self._thread is None:
114
+ raise RuntimeError('Thread not started: %r', self)
115
+ self._thread.join(timeout)
116
+
117
+
118
+ ##
119
+
120
+
121
+ class ThreadWorkerGroup:
122
+ @dc.dataclass()
123
+ class State:
124
+ worker: ThreadWorker
125
+
126
+ def __init__(self) -> None:
127
+ super().__init__()
128
+
129
+ self._lock = threading.RLock()
130
+ self._states: ta.Dict[ThreadWorker, ThreadWorkerGroup.State] = {}
131
+
132
+ def add(self, *workers: ThreadWorker) -> 'ThreadWorkerGroup':
133
+ with self._lock:
134
+ for w in workers:
135
+ if w in self._states:
136
+ raise KeyError(w)
137
+ self._states[w] = ThreadWorkerGroup.State(w)
138
+
139
+ return self
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ominfra
3
- Version: 0.0.0.dev102
3
+ Version: 0.0.0.dev104
4
4
  Summary: ominfra
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,8 +12,8 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
13
  Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omdev ==0.0.0.dev102
16
- Requires-Dist: omlish ==0.0.0.dev102
15
+ Requires-Dist: omdev ==0.0.0.dev104
16
+ Requires-Dist: omlish ==0.0.0.dev104
17
17
  Provides-Extra: all
18
18
  Requires-Dist: paramiko ~=3.5 ; extra == 'all'
19
19
  Requires-Dist: asyncssh ~=2.18 ; extra == 'all'
@@ -3,19 +3,24 @@ ominfra/__about__.py,sha256=6i1AoruFYQCd-PyhhbDQDWY2d1tiQu9nkwWr-fXAqfY,705
3
3
  ominfra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  ominfra/cmds.py,sha256=E0AfnvEmnKntXWvmLW5L05_NeDpBET1VBXn7vV6EwBQ,2083
5
5
  ominfra/ssh.py,sha256=jQpc4WvkMckIfk4vILda8zFaeharRqc_6wxW50b0OjQ,5431
6
- ominfra/threadworker.py,sha256=8rnWvgKjPIAdctS6wxiUiEIzm-mORRkWVD94YghVj0g,1413
6
+ ominfra/threadworkers.py,sha256=QuRpz9Yjyb4F8_IjzqmL7eNCAmXZfy3XLl7QoVF7Ohw,3273
7
7
  ominfra/clouds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  ominfra/clouds/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  ominfra/clouds/aws/__main__.py,sha256=HXMoxEl9KHhv6zOOPQxiJAftfR2SjBqeVTYw-og9aFw,163
10
10
  ominfra/clouds/aws/auth.py,sha256=p50hnm8SU4CWAkLX0C4XCTAm7yAAg-HqcP1YvL5cW94,6205
11
11
  ominfra/clouds/aws/cli.py,sha256=OJVVLIwSy1378drkgP1ke_JltbyzBmnrB_Lom6A83os,510
12
12
  ominfra/clouds/aws/dataclasses.py,sha256=rKhtJKJ0JhMssU9n9CABX_JaUiokIboEATJ9TZgZQ6A,3868
13
- ominfra/clouds/aws/logs.py,sha256=7Cl9vjco6G-5wW06TmuzU9GZ-diFP8V26X2UZnfJD3U,5232
13
+ ominfra/clouds/aws/logs.py,sha256=z9ouU2IYXNHsl7_Whbjs1FGtlUwsEq0RV8LNrM_QNTE,5471
14
14
  ominfra/clouds/aws/metadata.py,sha256=XR1BuMdQheyeFjjA3MN8GCNWVAp5ahoPdbWXEmViutQ,2767
15
15
  ominfra/clouds/aws/journald2aws/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
16
- ominfra/clouds/aws/journald2aws/main.py,sha256=d7jSbcaxjGgpVpDCPl1kJCOZg3S7g2n0Lf7gI0ZL3j0,9126
16
+ ominfra/clouds/aws/journald2aws/cursor.py,sha256=tQ7O6BHlEdaalbiI_Rqagj0aHfdtTQ_ZJwdOSRUjNvQ,1173
17
+ ominfra/clouds/aws/journald2aws/driver.py,sha256=8jiuEpOgKFSucpEJBBTBiSVg6L_tA4alUNK-I788HWU,5452
18
+ ominfra/clouds/aws/journald2aws/main.py,sha256=xFkEhkYKtFfW0XRfY0UaX_gd_FU66WTZOMCyiIaPY3E,2237
19
+ ominfra/clouds/aws/journald2aws/poster.py,sha256=hz1XuctW8GtLmfjhRvCFY6py52D4BzXHYny5XKFpHSA,2833
20
+ ominfra/clouds/gcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ ominfra/clouds/gcp/auth.py,sha256=3PyfRJNgajjMqJFem3SKui0CqGeHEsZlvbRhuxFcZG8,1348
17
22
  ominfra/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- ominfra/deploy/_executor.py,sha256=zHn4zAz6Ch1i5R_EdKTfJv_4SE0QPNuQEk7O1ptB_7A,32834
23
+ ominfra/deploy/_executor.py,sha256=3_ndcukzPt6Pc-5Cfnxz4OFjOYJefuTYM6ouijRjhTs,34042
19
24
  ominfra/deploy/configs.py,sha256=qi0kwT7G2NH7dXLOQic-u6R3yeadup_QtvrjwWIggbM,435
20
25
  ominfra/deploy/remote.py,sha256=6ACmpXU1uBdyGs3Xsp97ktKFq30cJlzN9LRWNUWlGY4,2144
21
26
  ominfra/deploy/executor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
@@ -30,7 +35,7 @@ ominfra/deploy/executor/concerns/systemd.py,sha256=MtsSEToEa1HNouern_JukcYTnypw_
30
35
  ominfra/deploy/executor/concerns/user.py,sha256=j5LDfQXquIp-eEM7t6aShsrYoQrM_ILXZycTmTcRVxA,686
31
36
  ominfra/deploy/executor/concerns/venv.py,sha256=jbRriqJHO4r9Zyo5Hfl_qVmcU6Qm6UgrouBroKcPn2g,775
32
37
  ominfra/deploy/poly/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
33
- ominfra/deploy/poly/_main.py,sha256=atzVWMa2FZlJYODcRxu5zN5CHOLiVW9aIS9f012QKWA,23569
38
+ ominfra/deploy/poly/_main.py,sha256=EtMN9Cmn4plMLTXq3u_NHUUhaa8qjsyldN61AbjDQEg,24025
34
39
  ominfra/deploy/poly/base.py,sha256=Bd-CzUTaDvTRbdXKiTxMxs77WCEXItwNoBYCRnTk1u4,4167
35
40
  ominfra/deploy/poly/configs.py,sha256=9bzWdbxhOk_Q4KokDjmRz254KHnUU71Vl1frLlhQyU4,584
36
41
  ominfra/deploy/poly/deploy.py,sha256=tMYKslXLjstcv86siRt5j37USsS0Wd6lsfeGRE26zio,544
@@ -42,18 +47,18 @@ ominfra/deploy/poly/site.py,sha256=QJwDDJoVm2-kxi4bxIrp-mn4y2qDLuW3CAUax3W8gv8,2
42
47
  ominfra/deploy/poly/supervisor.py,sha256=zkl6VQBcAZaMAhyR9DbbbqULcgFCDZoe9S_vP-mMFQ8,2289
43
48
  ominfra/deploy/poly/venv.py,sha256=BoipDEa4NTeodjf3L57KJfq9eGKLagFNKwD8pS4yrzA,1552
44
49
  ominfra/journald/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
- ominfra/journald/genmessages.py,sha256=3lB3W_Xl4GLAutNu1KvihdtMvkkukYqrfsamcqOS204,1583
50
+ ominfra/journald/genmessages.py,sha256=rLTS-K2v7otNOtTz4RoOEVYCm0fQuuBzf47e0T61tA8,1857
46
51
  ominfra/journald/messages.py,sha256=2iMY4k63XGNcN3LPvBmmK55ftjupnNh8f_ijlW9mkhQ,2208
47
- ominfra/journald/tailer.py,sha256=4CzBTQcAzlW9OQ--61fIdClZVgbMQQnYe2OD1d5P7e4,36780
52
+ ominfra/journald/tailer.py,sha256=-CTQPkDQUBJJOpQCueFDsF5VmlfPSaSrbrGB505SUuM,36819
48
53
  ominfra/manage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
54
  ominfra/manage/manage.py,sha256=BttL8LFEknHZE_h2Pt5dAqbfUkv6qy43WI0raXBZ1a8,151
50
55
  ominfra/pyremote/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
- ominfra/pyremote/_runcommands.py,sha256=2UVHaUJjmWP8jMZE79j2Qk1E5IOyVV1qNSUbdr-zKYM,26670
56
+ ominfra/pyremote/_runcommands.py,sha256=IGFDDcmXJDmhGv7AFAAjkCJc615YQGUsNvn5vTAYReY,27878
52
57
  ominfra/pyremote/bootstrap.py,sha256=RvMO3YGaN1E4sgUi1JEtiPak8cjvqtc_vRCq1yqbeZg,3370
53
58
  ominfra/pyremote/runcommands.py,sha256=bviS0_TDIoZVAe4h-_iavbvJtVSFu8lnk7fQ5iasCWE,1571
54
59
  ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- ominfra/scripts/journald2aws.py,sha256=AgOHKPujUo4SqTFoz_EiN-oJ-HwZJB-UNyCFJypsNus,91403
56
- ominfra/scripts/supervisor.py,sha256=iWTZQIrzqNjlmuDH489AlfXGb0i_0sfoYIYP7h1LH-E,115374
60
+ ominfra/scripts/journald2aws.py,sha256=ZI6SppxsDEwnjk0zaBmAmhyi3-3VVbWubDkeGz_DEU8,98035
61
+ ominfra/scripts/supervisor.py,sha256=Qf6WKD_4EkC_5QWimApONAAs3lvcAKK2X7nOaYDex48,116162
57
62
  ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
58
63
  ominfra/supervisor/__main__.py,sha256=usW9jjq5JPe_2SL8H5PrjDdksO75MX85Ir0HFfb35eM,72
59
64
  ominfra/supervisor/compat.py,sha256=Y1d_pk4eN18AbVYjDHAXMMnPwOKTFpc7JDb1uClYMsQ,5064
@@ -73,9 +78,9 @@ ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
73
78
  ominfra/tailscale/cli.py,sha256=DSGp4hn5xwOW-l_u_InKlSF6kIobxtUtVssf_73STs0,3567
74
79
  ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
80
  ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
76
- ominfra-0.0.0.dev102.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
77
- ominfra-0.0.0.dev102.dist-info/METADATA,sha256=204uohL25Cyu3_Op6fWaH6j4qlPBlc60pKcNBCjU8SU,742
78
- ominfra-0.0.0.dev102.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
79
- ominfra-0.0.0.dev102.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
80
- ominfra-0.0.0.dev102.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
81
- ominfra-0.0.0.dev102.dist-info/RECORD,,
81
+ ominfra-0.0.0.dev104.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
82
+ ominfra-0.0.0.dev104.dist-info/METADATA,sha256=6dWv52GEcIq4huozhiXk8aClmrjz-5u0kcanUmUIiQs,742
83
+ ominfra-0.0.0.dev104.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
84
+ ominfra-0.0.0.dev104.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
85
+ ominfra-0.0.0.dev104.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
86
+ ominfra-0.0.0.dev104.dist-info/RECORD,,
ominfra/threadworker.py DELETED
@@ -1,67 +0,0 @@
1
- # ruff: noqa: UP007
2
- # @omlish-lite
3
- """
4
- TODO:
5
- - implement stop lol
6
- - collective heartbeat monitoring - ThreadWorkerGroups
7
- """
8
- import abc
9
- import threading
10
- import time
11
- import typing as ta
12
-
13
- from omlish.lite.logs import log
14
-
15
-
16
- class ThreadWorker(abc.ABC):
17
- def __init__(
18
- self,
19
- *,
20
- stop_event: ta.Optional[threading.Event] = None,
21
- ) -> None:
22
- super().__init__()
23
-
24
- if stop_event is None:
25
- stop_event = threading.Event()
26
- self._stop_event = stop_event
27
-
28
- self._thread: ta.Optional[threading.Thread] = None
29
-
30
- self._last_heartbeat: ta.Optional[float] = None
31
-
32
- #
33
-
34
- def should_stop(self) -> bool:
35
- return self._stop_event.is_set()
36
-
37
- #
38
-
39
- @property
40
- def last_heartbeat(self) -> ta.Optional[float]:
41
- return self._last_heartbeat
42
-
43
- def _heartbeat(self) -> bool:
44
- self._last_heartbeat = time.time()
45
-
46
- if self.should_stop():
47
- log.info('Stopping: %s', self)
48
- return False
49
-
50
- return True
51
-
52
- #
53
-
54
- def is_alive(self) -> bool:
55
- return (thr := self._thread) is not None and thr.is_alive()
56
-
57
- def start(self) -> None:
58
- thr = threading.Thread(target=self._run)
59
- self._thread = thr
60
- thr.start()
61
-
62
- @abc.abstractmethod
63
- def _run(self) -> None:
64
- raise NotImplementedError
65
-
66
- def stop(self) -> None:
67
- raise NotImplementedError