ominfra 0.0.0.dev128__py3-none-any.whl → 0.0.0.dev130__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ominfra/deploy/_executor.py +39 -0
- ominfra/pyremote/_runcommands.py +39 -0
- ominfra/scripts/journald2aws.py +136 -0
- ominfra/scripts/supervisor.py +1732 -880
- ominfra/supervisor/dispatchers.py +10 -9
- ominfra/supervisor/dispatchersimpl.py +20 -18
- ominfra/supervisor/groups.py +16 -1
- ominfra/supervisor/groupsimpl.py +2 -2
- ominfra/supervisor/http.py +130 -0
- ominfra/supervisor/inject.py +61 -17
- ominfra/supervisor/io.py +97 -0
- ominfra/supervisor/main.py +5 -6
- ominfra/supervisor/processimpl.py +10 -18
- ominfra/supervisor/signals.py +66 -0
- ominfra/supervisor/spawningimpl.py +11 -11
- ominfra/supervisor/supervisor.py +70 -137
- ominfra/supervisor/types.py +21 -58
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev130.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev130.dist-info}/RECORD +23 -22
- ominfra/supervisor/context.py +0 -80
- ominfra/supervisor/poller.py +0 -240
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev130.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev130.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev130.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev130.dist-info}/top_level.txt +0 -0
ominfra/supervisor/types.py
CHANGED
@@ -3,13 +3,13 @@ import abc
|
|
3
3
|
import functools
|
4
4
|
import typing as ta
|
5
5
|
|
6
|
+
from omlish.lite.fdio.handlers import FdIoHandler
|
7
|
+
|
6
8
|
from .configs import ProcessConfig
|
7
9
|
from .configs import ProcessGroupConfig
|
8
|
-
from .configs import ServerConfig
|
9
10
|
from .states import ProcessState
|
10
11
|
from .states import SupervisorState
|
11
12
|
from .utils.collections import KeyedCollectionAccessors
|
12
|
-
from .utils.ostypes import Fd
|
13
13
|
from .utils.ostypes import Pid
|
14
14
|
from .utils.ostypes import Rc
|
15
15
|
|
@@ -21,6 +21,10 @@ if ta.TYPE_CHECKING:
|
|
21
21
|
##
|
22
22
|
|
23
23
|
|
24
|
+
class ExitNow(Exception): # noqa
|
25
|
+
pass
|
26
|
+
|
27
|
+
|
24
28
|
ServerEpoch = ta.NewType('ServerEpoch', int)
|
25
29
|
|
26
30
|
|
@@ -44,12 +48,7 @@ class ConfigPriorityOrdered(abc.ABC):
|
|
44
48
|
##
|
45
49
|
|
46
50
|
|
47
|
-
class
|
48
|
-
@property
|
49
|
-
@abc.abstractmethod
|
50
|
-
def config(self) -> ServerConfig:
|
51
|
-
raise NotImplementedError
|
52
|
-
|
51
|
+
class SupervisorStateManager(abc.ABC):
|
53
52
|
@property
|
54
53
|
@abc.abstractmethod
|
55
54
|
def state(self) -> SupervisorState:
|
@@ -63,57 +62,25 @@ class ServerContext(abc.ABC):
|
|
63
62
|
##
|
64
63
|
|
65
64
|
|
66
|
-
class
|
67
|
-
@property
|
65
|
+
class HasDispatchers(abc.ABC):
|
68
66
|
@abc.abstractmethod
|
69
|
-
def
|
67
|
+
def get_dispatchers(self) -> 'Dispatchers':
|
70
68
|
raise NotImplementedError
|
71
69
|
|
72
|
-
@property
|
73
|
-
@abc.abstractmethod
|
74
|
-
def channel(self) -> str:
|
75
|
-
raise NotImplementedError
|
76
70
|
|
71
|
+
class ProcessDispatcher(FdIoHandler, abc.ABC):
|
77
72
|
@property
|
78
73
|
@abc.abstractmethod
|
79
|
-
def
|
74
|
+
def channel(self) -> str:
|
80
75
|
raise NotImplementedError
|
81
76
|
|
82
77
|
@property
|
83
78
|
@abc.abstractmethod
|
84
|
-
def
|
85
|
-
raise NotImplementedError
|
86
|
-
|
87
|
-
#
|
88
|
-
|
89
|
-
@abc.abstractmethod
|
90
|
-
def close(self) -> None:
|
91
|
-
raise NotImplementedError
|
92
|
-
|
93
|
-
@abc.abstractmethod
|
94
|
-
def handle_error(self) -> None:
|
95
|
-
raise NotImplementedError
|
96
|
-
|
97
|
-
#
|
98
|
-
|
99
|
-
@abc.abstractmethod
|
100
|
-
def readable(self) -> bool:
|
101
|
-
raise NotImplementedError
|
102
|
-
|
103
|
-
@abc.abstractmethod
|
104
|
-
def writable(self) -> bool:
|
79
|
+
def process(self) -> 'Process':
|
105
80
|
raise NotImplementedError
|
106
81
|
|
107
|
-
#
|
108
|
-
|
109
|
-
def handle_read_event(self) -> None:
|
110
|
-
raise TypeError
|
111
|
-
|
112
|
-
def handle_write_event(self) -> None:
|
113
|
-
raise TypeError
|
114
|
-
|
115
82
|
|
116
|
-
class
|
83
|
+
class ProcessOutputDispatcher(ProcessDispatcher, abc.ABC):
|
117
84
|
@abc.abstractmethod
|
118
85
|
def remove_logs(self) -> None:
|
119
86
|
raise NotImplementedError
|
@@ -123,7 +90,7 @@ class OutputDispatcher(Dispatcher, abc.ABC):
|
|
123
90
|
raise NotImplementedError
|
124
91
|
|
125
92
|
|
126
|
-
class
|
93
|
+
class ProcessInputDispatcher(ProcessDispatcher, abc.ABC):
|
127
94
|
@abc.abstractmethod
|
128
95
|
def write(self, chars: ta.Union[bytes, str]) -> None:
|
129
96
|
raise NotImplementedError
|
@@ -136,7 +103,11 @@ class InputDispatcher(Dispatcher, abc.ABC):
|
|
136
103
|
##
|
137
104
|
|
138
105
|
|
139
|
-
class Process(
|
106
|
+
class Process(
|
107
|
+
ConfigPriorityOrdered,
|
108
|
+
HasDispatchers,
|
109
|
+
abc.ABC,
|
110
|
+
):
|
140
111
|
@property
|
141
112
|
@abc.abstractmethod
|
142
113
|
def name(self) -> str:
|
@@ -159,11 +130,6 @@ class Process(ConfigPriorityOrdered, abc.ABC):
|
|
159
130
|
|
160
131
|
#
|
161
132
|
|
162
|
-
@property
|
163
|
-
@abc.abstractmethod
|
164
|
-
def context(self) -> ServerContext:
|
165
|
-
raise NotImplementedError
|
166
|
-
|
167
133
|
@abc.abstractmethod
|
168
134
|
def finish(self, sts: Rc) -> None:
|
169
135
|
raise NotImplementedError
|
@@ -180,18 +146,15 @@ class Process(ConfigPriorityOrdered, abc.ABC):
|
|
180
146
|
def transition(self) -> None:
|
181
147
|
raise NotImplementedError
|
182
148
|
|
149
|
+
@property
|
183
150
|
@abc.abstractmethod
|
184
|
-
def
|
151
|
+
def state(self) -> ProcessState:
|
185
152
|
raise NotImplementedError
|
186
153
|
|
187
154
|
@abc.abstractmethod
|
188
155
|
def after_setuid(self) -> None:
|
189
156
|
raise NotImplementedError
|
190
157
|
|
191
|
-
@abc.abstractmethod
|
192
|
-
def get_dispatchers(self) -> 'Dispatchers':
|
193
|
-
raise NotImplementedError
|
194
|
-
|
195
158
|
|
196
159
|
##
|
197
160
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ominfra
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev130
|
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.
|
16
|
-
Requires-Dist: omlish==0.0.0.
|
15
|
+
Requires-Dist: omdev==0.0.0.dev130
|
16
|
+
Requires-Dist: omlish==0.0.0.dev130
|
17
17
|
Provides-Extra: all
|
18
18
|
Requires-Dist: paramiko~=3.5; extra == "all"
|
19
19
|
Requires-Dist: asyncssh~=2.18; extra == "all"
|
@@ -22,7 +22,7 @@ ominfra/clouds/aws/journald2aws/poster.py,sha256=hz1XuctW8GtLmfjhRvCFY6py52D4BzX
|
|
22
22
|
ominfra/clouds/gcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
23
|
ominfra/clouds/gcp/auth.py,sha256=3PyfRJNgajjMqJFem3SKui0CqGeHEsZlvbRhuxFcZG8,1348
|
24
24
|
ominfra/deploy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
25
|
-
ominfra/deploy/_executor.py,sha256=
|
25
|
+
ominfra/deploy/_executor.py,sha256=3h7ViDW9WtF__sI_qK88SUgldalqdnpf5AlJGbCF9TY,35361
|
26
26
|
ominfra/deploy/configs.py,sha256=qi0kwT7G2NH7dXLOQic-u6R3yeadup_QtvrjwWIggbM,435
|
27
27
|
ominfra/deploy/remote.py,sha256=6ACmpXU1uBdyGs3Xsp97ktKFq30cJlzN9LRWNUWlGY4,2144
|
28
28
|
ominfra/deploy/executor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
@@ -56,37 +56,38 @@ ominfra/journald/tailer.py,sha256=5abcFMfgi7fnY9ZEQe2ZVobaJxjQkeu6d9Kagw33a1w,33
|
|
56
56
|
ominfra/manage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
57
|
ominfra/manage/manage.py,sha256=BttL8LFEknHZE_h2Pt5dAqbfUkv6qy43WI0raXBZ1a8,151
|
58
58
|
ominfra/pyremote/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
59
|
-
ominfra/pyremote/_runcommands.py,sha256=
|
59
|
+
ominfra/pyremote/_runcommands.py,sha256=TfO2cwXbw_1T-c_NDM7K8gWYJbU20Y3k9qEIOM3S6BI,29194
|
60
60
|
ominfra/pyremote/bootstrap.py,sha256=RvMO3YGaN1E4sgUi1JEtiPak8cjvqtc_vRCq1yqbeZg,3370
|
61
61
|
ominfra/pyremote/runcommands.py,sha256=bviS0_TDIoZVAe4h-_iavbvJtVSFu8lnk7fQ5iasCWE,1571
|
62
62
|
ominfra/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
63
|
-
ominfra/scripts/journald2aws.py,sha256=
|
64
|
-
ominfra/scripts/supervisor.py,sha256=
|
63
|
+
ominfra/scripts/journald2aws.py,sha256=FmjNwUPQDCOmIbUxwkN7mNHATf_lXf1uwp0ST71IHFA,131405
|
64
|
+
ominfra/scripts/supervisor.py,sha256=DHvE1h2s57IvHEIZnqsmhx7BrrO20Qbd21IwkQGasmM,242622
|
65
65
|
ominfra/supervisor/LICENSE.txt,sha256=yvqaMNsDhWxziHa9ien6qCW1SkZv-DQlAg96XjfSee8,1746
|
66
66
|
ominfra/supervisor/__init__.py,sha256=Y3l4WY4JRi2uLG6kgbGp93fuGfkxkKwZDvhsa0Rwgtk,15
|
67
67
|
ominfra/supervisor/__main__.py,sha256=I0yFw-C08OOiZ3BF6lF1Oiv789EQXu-_j6whDhQUTEA,66
|
68
68
|
ominfra/supervisor/configs.py,sha256=AhBlbifwDXc0acEhcbdv9jphJL-SBFODFDAWDVckzAE,3945
|
69
|
-
ominfra/supervisor/
|
70
|
-
ominfra/supervisor/
|
71
|
-
ominfra/supervisor/dispatchersimpl.py,sha256=t1VFcofj1kTH1q13Z-S1OUTXixPwgSqJkh5A5IkHKPA,10956
|
69
|
+
ominfra/supervisor/dispatchers.py,sha256=dfjog5PyVAJaFzgFI0tpy38ZgDiFrewMjVi21ksrlAg,1007
|
70
|
+
ominfra/supervisor/dispatchersimpl.py,sha256=k86MSDxIHInOBopYehNuCDcSM_QsxrrGuME0UjnSs_o,11249
|
72
71
|
ominfra/supervisor/events.py,sha256=w3HQFrq-SuroYWoQfNFYeU1phnTvHTgsAqA6TGtAafI,6593
|
73
72
|
ominfra/supervisor/exceptions.py,sha256=Qbu211H3CLlSmi9LsSikOwrcL5HgJP9ugvcKWlGTAoI,750
|
74
|
-
ominfra/supervisor/groups.py,sha256=
|
75
|
-
ominfra/supervisor/groupsimpl.py,sha256=
|
76
|
-
ominfra/supervisor/
|
77
|
-
ominfra/supervisor/
|
73
|
+
ominfra/supervisor/groups.py,sha256=MBbsbt8Zh_WEYkGOr1KXa82gnPVw9wPB2lAnqhugXSc,2457
|
74
|
+
ominfra/supervisor/groupsimpl.py,sha256=nIrW4SmB0W6c2jOR_HhkfVcH4eHyLZnG1FJ0MCzc6mQ,2292
|
75
|
+
ominfra/supervisor/http.py,sha256=y0tos6zbb4k-WvNQXlgAeK1qi5mKXkyXO9bVJt4OXew,3227
|
76
|
+
ominfra/supervisor/inject.py,sha256=onKUudx5eBbNuXwEqeiaVIIA3ZbpUSDiEAKg9GBiWG8,4514
|
77
|
+
ominfra/supervisor/io.py,sha256=2NO4BYC-PznIrJpTFxN8UEAhd_codfNm_HI424gYQ3c,3294
|
78
|
+
ominfra/supervisor/main.py,sha256=ebe7skFPfwXV2meMVRndhuLZmz-LiuHH1x1CgiarR0o,4132
|
78
79
|
ominfra/supervisor/pipes.py,sha256=XrJ9lD04tPdzZD3xhhYKxpBKHWhZ0Ii315E78bgj7ws,2233
|
79
|
-
ominfra/supervisor/poller.py,sha256=LnQVttPCm8a1UtnDvsho6zLw8NP-2_2VUiNM-d0w_FU,7776
|
80
80
|
ominfra/supervisor/privileges.py,sha256=bO7rJGT7cMOBALK_4D4NiQnOS5dOYb14Sz66R-ymG24,2071
|
81
81
|
ominfra/supervisor/process.py,sha256=UaubVxsxVqDnbuWVpTH0DTGbJGLO0vGJ9mNcvy2kCXM,217
|
82
|
-
ominfra/supervisor/processimpl.py,sha256=
|
82
|
+
ominfra/supervisor/processimpl.py,sha256=vpyRVOYV8_AW5eCtgAa2LKWyW9FiqA5bKmBqF1KYE5c,18715
|
83
83
|
ominfra/supervisor/setup.py,sha256=7HwwwI-WT_Z0WjZ9_l5Orr4K298nKKhQ1f_ZgGsi9TU,622
|
84
84
|
ominfra/supervisor/setupimpl.py,sha256=S_YgCH3XzLsFIAriJROvDMUDh7OzVVJoxzEzCkbb4g4,9648
|
85
|
+
ominfra/supervisor/signals.py,sha256=jY52naUifcAjd6nICTP1ZW3IQSPsHB4cvbsJo8_QV_U,2196
|
85
86
|
ominfra/supervisor/spawning.py,sha256=i1k3tmqWyU-KIN7kel-JVxTVGnLiTIVmZzlstJSZpjM,622
|
86
|
-
ominfra/supervisor/spawningimpl.py,sha256=
|
87
|
+
ominfra/supervisor/spawningimpl.py,sha256=Med8UJH7vP3IaihTJIaqfndhB5mD5wht6Feim674HKs,11161
|
87
88
|
ominfra/supervisor/states.py,sha256=9yoNOSwalRcKEnCP9zG6tVS0oivo5tCeuH6AaaW7Jpc,890
|
88
|
-
ominfra/supervisor/supervisor.py,sha256=
|
89
|
-
ominfra/supervisor/types.py,sha256=
|
89
|
+
ominfra/supervisor/supervisor.py,sha256=XiLVq8qMLKGR50yTgW5njtqVkZCupf-cXDjmh7bJtXQ,9515
|
90
|
+
ominfra/supervisor/types.py,sha256=RamAYEF3fISfKwlIMRleLOFuKVWrxjQJGI6p76jK03c,3959
|
90
91
|
ominfra/supervisor/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
91
92
|
ominfra/supervisor/utils/collections.py,sha256=vcfmVYS4QngMdtEI1DvdRIcubmy55Wj40NCzW27_rIY,1361
|
92
93
|
ominfra/supervisor/utils/diag.py,sha256=ujz4gkW7p3wmbaKFM8Hz5eHEwpoUkbB8JeDvcHilCz0,705
|
@@ -102,9 +103,9 @@ ominfra/tailscale/api.py,sha256=C5-t_b6jZXUWcy5k8bXm7CFnk73pSdrlMOgGDeGVrpw,1370
|
|
102
103
|
ominfra/tailscale/cli.py,sha256=DSGp4hn5xwOW-l_u_InKlSF6kIobxtUtVssf_73STs0,3567
|
103
104
|
ominfra/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
104
105
|
ominfra/tools/listresources.py,sha256=4qVg5txsb10EHhvqXXeM6gJ2jx9LbroEnPydDv1uXs0,6176
|
105
|
-
ominfra-0.0.0.
|
106
|
-
ominfra-0.0.0.
|
107
|
-
ominfra-0.0.0.
|
108
|
-
ominfra-0.0.0.
|
109
|
-
ominfra-0.0.0.
|
110
|
-
ominfra-0.0.0.
|
106
|
+
ominfra-0.0.0.dev130.dist-info/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
|
107
|
+
ominfra-0.0.0.dev130.dist-info/METADATA,sha256=PjbMdzNCdOt4JYdmoDTM92oJu056qJOvTng2oncmCIU,731
|
108
|
+
ominfra-0.0.0.dev130.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
109
|
+
ominfra-0.0.0.dev130.dist-info/entry_points.txt,sha256=kgecQ2MgGrM9qK744BoKS3tMesaC3yjLnl9pa5CRczg,37
|
110
|
+
ominfra-0.0.0.dev130.dist-info/top_level.txt,sha256=E-b2OHkk_AOBLXHYZQ2EOFKl-_6uOGd8EjeG-Zy6h_w,8
|
111
|
+
ominfra-0.0.0.dev130.dist-info/RECORD,,
|
ominfra/supervisor/context.py
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
# ruff: noqa: UP006 UP007
|
2
|
-
import errno
|
3
|
-
import os
|
4
|
-
import typing as ta
|
5
|
-
|
6
|
-
from omlish.lite.logs import log
|
7
|
-
|
8
|
-
from .configs import ServerConfig
|
9
|
-
from .poller import Poller
|
10
|
-
from .states import SupervisorState
|
11
|
-
from .types import ServerContext
|
12
|
-
from .types import ServerEpoch
|
13
|
-
from .utils.fs import mktempfile
|
14
|
-
from .utils.ostypes import Pid
|
15
|
-
from .utils.ostypes import Rc
|
16
|
-
|
17
|
-
|
18
|
-
class ServerContextImpl(ServerContext):
|
19
|
-
def __init__(
|
20
|
-
self,
|
21
|
-
config: ServerConfig,
|
22
|
-
poller: Poller,
|
23
|
-
*,
|
24
|
-
epoch: ServerEpoch = ServerEpoch(0),
|
25
|
-
) -> None:
|
26
|
-
super().__init__()
|
27
|
-
|
28
|
-
self._config = config
|
29
|
-
self._poller = poller
|
30
|
-
self._epoch = epoch
|
31
|
-
|
32
|
-
self._state: SupervisorState = SupervisorState.RUNNING
|
33
|
-
|
34
|
-
@property
|
35
|
-
def config(self) -> ServerConfig:
|
36
|
-
return self._config
|
37
|
-
|
38
|
-
@property
|
39
|
-
def epoch(self) -> ServerEpoch:
|
40
|
-
return self._epoch
|
41
|
-
|
42
|
-
@property
|
43
|
-
def first(self) -> bool:
|
44
|
-
return not self._epoch
|
45
|
-
|
46
|
-
@property
|
47
|
-
def state(self) -> SupervisorState:
|
48
|
-
return self._state
|
49
|
-
|
50
|
-
def set_state(self, state: SupervisorState) -> None:
|
51
|
-
self._state = state
|
52
|
-
|
53
|
-
#
|
54
|
-
|
55
|
-
def waitpid(self) -> ta.Tuple[ta.Optional[Pid], ta.Optional[Rc]]:
|
56
|
-
# Need pthread_sigmask here to avoid concurrent sigchld, but Python doesn't offer in Python < 3.4. There is
|
57
|
-
# still a race condition here; we can get a sigchld while we're sitting in the waitpid call. However, AFAICT, if
|
58
|
-
# waitpid is interrupted by SIGCHLD, as long as we call waitpid again (which happens every so often during the
|
59
|
-
# normal course in the mainloop), we'll eventually reap the child that we tried to reap during the interrupted
|
60
|
-
# call. At least on Linux, this appears to be true, or at least stopping 50 processes at once never left zombies
|
61
|
-
# lying around.
|
62
|
-
try:
|
63
|
-
pid, sts = os.waitpid(-1, os.WNOHANG)
|
64
|
-
except OSError as exc:
|
65
|
-
code = exc.args[0]
|
66
|
-
if code not in (errno.ECHILD, errno.EINTR):
|
67
|
-
log.critical('waitpid error %r; a process may not be cleaned up properly', code)
|
68
|
-
if code == errno.EINTR:
|
69
|
-
log.debug('EINTR during reap')
|
70
|
-
pid, sts = None, None
|
71
|
-
return pid, sts # type: ignore
|
72
|
-
|
73
|
-
def get_auto_child_log_name(self, name: str, identifier: str, channel: str) -> str:
|
74
|
-
prefix = f'{name}-{channel}---{identifier}-'
|
75
|
-
logfile = mktempfile(
|
76
|
-
suffix='.log',
|
77
|
-
prefix=prefix,
|
78
|
-
dir=self.config.child_logdir,
|
79
|
-
)
|
80
|
-
return logfile
|
ominfra/supervisor/poller.py
DELETED
@@ -1,240 +0,0 @@
|
|
1
|
-
# ruff: noqa: UP006 UP007
|
2
|
-
import abc
|
3
|
-
import errno
|
4
|
-
import select
|
5
|
-
import sys
|
6
|
-
import typing as ta
|
7
|
-
|
8
|
-
from omlish.lite.logs import log
|
9
|
-
|
10
|
-
from .setup import DaemonizeListener
|
11
|
-
from .utils.ostypes import Fd
|
12
|
-
|
13
|
-
|
14
|
-
class Poller(DaemonizeListener, abc.ABC):
|
15
|
-
def __init__(self) -> None:
|
16
|
-
super().__init__()
|
17
|
-
|
18
|
-
@abc.abstractmethod
|
19
|
-
def register_readable(self, fd: Fd) -> None:
|
20
|
-
raise NotImplementedError
|
21
|
-
|
22
|
-
@abc.abstractmethod
|
23
|
-
def register_writable(self, fd: Fd) -> None:
|
24
|
-
raise NotImplementedError
|
25
|
-
|
26
|
-
@abc.abstractmethod
|
27
|
-
def unregister_readable(self, fd: Fd) -> None:
|
28
|
-
raise NotImplementedError
|
29
|
-
|
30
|
-
@abc.abstractmethod
|
31
|
-
def unregister_writable(self, fd: Fd) -> None:
|
32
|
-
raise NotImplementedError
|
33
|
-
|
34
|
-
@abc.abstractmethod
|
35
|
-
def poll(self, timeout: ta.Optional[float]) -> ta.Tuple[ta.List[Fd], ta.List[Fd]]:
|
36
|
-
raise NotImplementedError
|
37
|
-
|
38
|
-
def before_daemonize(self) -> None: # noqa
|
39
|
-
pass
|
40
|
-
|
41
|
-
def after_daemonize(self) -> None: # noqa
|
42
|
-
pass
|
43
|
-
|
44
|
-
def close(self) -> None: # noqa
|
45
|
-
pass
|
46
|
-
|
47
|
-
|
48
|
-
class SelectPoller(Poller):
|
49
|
-
def __init__(self) -> None:
|
50
|
-
super().__init__()
|
51
|
-
|
52
|
-
self._readable: ta.Set[Fd] = set()
|
53
|
-
self._writable: ta.Set[Fd] = set()
|
54
|
-
|
55
|
-
def register_readable(self, fd: Fd) -> None:
|
56
|
-
self._readable.add(fd)
|
57
|
-
|
58
|
-
def register_writable(self, fd: Fd) -> None:
|
59
|
-
self._writable.add(fd)
|
60
|
-
|
61
|
-
def unregister_readable(self, fd: Fd) -> None:
|
62
|
-
self._readable.discard(fd)
|
63
|
-
|
64
|
-
def unregister_writable(self, fd: Fd) -> None:
|
65
|
-
self._writable.discard(fd)
|
66
|
-
|
67
|
-
def unregister_all(self) -> None:
|
68
|
-
self._readable.clear()
|
69
|
-
self._writable.clear()
|
70
|
-
|
71
|
-
def poll(self, timeout: ta.Optional[float]) -> ta.Tuple[ta.List[Fd], ta.List[Fd]]:
|
72
|
-
try:
|
73
|
-
r, w, x = select.select(
|
74
|
-
self._readable,
|
75
|
-
self._writable,
|
76
|
-
[], timeout,
|
77
|
-
)
|
78
|
-
except OSError as exc:
|
79
|
-
if exc.args[0] == errno.EINTR:
|
80
|
-
log.debug('EINTR encountered in poll')
|
81
|
-
return [], []
|
82
|
-
if exc.args[0] == errno.EBADF:
|
83
|
-
log.debug('EBADF encountered in poll')
|
84
|
-
self.unregister_all()
|
85
|
-
return [], []
|
86
|
-
raise
|
87
|
-
return r, w
|
88
|
-
|
89
|
-
|
90
|
-
class PollPoller(Poller):
|
91
|
-
_READ = select.POLLIN | select.POLLPRI | select.POLLHUP
|
92
|
-
_WRITE = select.POLLOUT
|
93
|
-
|
94
|
-
def __init__(self) -> None:
|
95
|
-
super().__init__()
|
96
|
-
|
97
|
-
self._poller = select.poll()
|
98
|
-
self._readable: set[Fd] = set()
|
99
|
-
self._writable: set[Fd] = set()
|
100
|
-
|
101
|
-
def register_readable(self, fd: Fd) -> None:
|
102
|
-
self._poller.register(fd, self._READ)
|
103
|
-
self._readable.add(fd)
|
104
|
-
|
105
|
-
def register_writable(self, fd: Fd) -> None:
|
106
|
-
self._poller.register(fd, self._WRITE)
|
107
|
-
self._writable.add(fd)
|
108
|
-
|
109
|
-
def unregister_readable(self, fd: Fd) -> None:
|
110
|
-
self._readable.discard(fd)
|
111
|
-
self._poller.unregister(fd)
|
112
|
-
if fd in self._writable:
|
113
|
-
self._poller.register(fd, self._WRITE)
|
114
|
-
|
115
|
-
def unregister_writable(self, fd: Fd) -> None:
|
116
|
-
self._writable.discard(fd)
|
117
|
-
self._poller.unregister(fd)
|
118
|
-
if fd in self._readable:
|
119
|
-
self._poller.register(fd, self._READ)
|
120
|
-
|
121
|
-
def poll(self, timeout: ta.Optional[float]) -> ta.Tuple[ta.List[Fd], ta.List[Fd]]:
|
122
|
-
fds = self._poll_fds(timeout) # type: ignore
|
123
|
-
readable, writable = [], []
|
124
|
-
for fd, eventmask in fds:
|
125
|
-
if self._ignore_invalid(fd, eventmask):
|
126
|
-
continue
|
127
|
-
if eventmask & self._READ:
|
128
|
-
readable.append(fd)
|
129
|
-
if eventmask & self._WRITE:
|
130
|
-
writable.append(fd)
|
131
|
-
return readable, writable
|
132
|
-
|
133
|
-
def _poll_fds(self, timeout: float) -> ta.List[ta.Tuple[Fd, Fd]]:
|
134
|
-
try:
|
135
|
-
return self._poller.poll(timeout * 1000) # type: ignore
|
136
|
-
except OSError as exc:
|
137
|
-
if exc.args[0] == errno.EINTR:
|
138
|
-
log.debug('EINTR encountered in poll')
|
139
|
-
return []
|
140
|
-
raise
|
141
|
-
|
142
|
-
def _ignore_invalid(self, fd: Fd, eventmask: int) -> bool:
|
143
|
-
if eventmask & select.POLLNVAL:
|
144
|
-
# POLLNVAL means `fd` value is invalid, not open. When a process quits it's `fd`s are closed so there is no
|
145
|
-
# more reason to keep this `fd` registered If the process restarts it's `fd`s are registered again.
|
146
|
-
self._poller.unregister(fd)
|
147
|
-
self._readable.discard(fd)
|
148
|
-
self._writable.discard(fd)
|
149
|
-
return True
|
150
|
-
return False
|
151
|
-
|
152
|
-
|
153
|
-
if sys.platform == 'darwin' or sys.platform.startswith('freebsd'):
|
154
|
-
class KqueuePoller(Poller):
|
155
|
-
max_events = 1000
|
156
|
-
|
157
|
-
def __init__(self) -> None:
|
158
|
-
super().__init__()
|
159
|
-
|
160
|
-
self._kqueue: ta.Optional[ta.Any] = select.kqueue()
|
161
|
-
self._readable: set[Fd] = set()
|
162
|
-
self._writable: set[Fd] = set()
|
163
|
-
|
164
|
-
def register_readable(self, fd: Fd) -> None:
|
165
|
-
self._readable.add(fd)
|
166
|
-
kevent = select.kevent(fd, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD)
|
167
|
-
self._kqueue_control(fd, kevent)
|
168
|
-
|
169
|
-
def register_writable(self, fd: Fd) -> None:
|
170
|
-
self._writable.add(fd)
|
171
|
-
kevent = select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_ADD)
|
172
|
-
self._kqueue_control(fd, kevent)
|
173
|
-
|
174
|
-
def unregister_readable(self, fd: Fd) -> None:
|
175
|
-
kevent = select.kevent(fd, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_DELETE)
|
176
|
-
self._readable.discard(fd)
|
177
|
-
self._kqueue_control(fd, kevent)
|
178
|
-
|
179
|
-
def unregister_writable(self, fd: Fd) -> None:
|
180
|
-
kevent = select.kevent(fd, filter=select.KQ_FILTER_WRITE, flags=select.KQ_EV_DELETE)
|
181
|
-
self._writable.discard(fd)
|
182
|
-
self._kqueue_control(fd, kevent)
|
183
|
-
|
184
|
-
def _kqueue_control(self, fd: Fd, kevent: 'select.kevent') -> None:
|
185
|
-
try:
|
186
|
-
self._kqueue.control([kevent], 0) # type: ignore
|
187
|
-
except OSError as error:
|
188
|
-
if error.errno == errno.EBADF:
|
189
|
-
log.debug('EBADF encountered in kqueue. Invalid file descriptor %s', fd)
|
190
|
-
else:
|
191
|
-
raise
|
192
|
-
|
193
|
-
def poll(self, timeout: ta.Optional[float]) -> ta.Tuple[ta.List[Fd], ta.List[Fd]]:
|
194
|
-
readable, writable = [], [] # type: ignore
|
195
|
-
|
196
|
-
try:
|
197
|
-
kevents = self._kqueue.control(None, self.max_events, timeout) # type: ignore
|
198
|
-
except OSError as error:
|
199
|
-
if error.errno == errno.EINTR:
|
200
|
-
log.debug('EINTR encountered in poll')
|
201
|
-
return readable, writable
|
202
|
-
raise
|
203
|
-
|
204
|
-
for kevent in kevents:
|
205
|
-
if kevent.filter == select.KQ_FILTER_READ:
|
206
|
-
readable.append(kevent.ident)
|
207
|
-
if kevent.filter == select.KQ_FILTER_WRITE:
|
208
|
-
writable.append(kevent.ident)
|
209
|
-
|
210
|
-
return readable, writable
|
211
|
-
|
212
|
-
def before_daemonize(self) -> None:
|
213
|
-
self.close()
|
214
|
-
|
215
|
-
def after_daemonize(self) -> None:
|
216
|
-
self._kqueue = select.kqueue()
|
217
|
-
for fd in self._readable:
|
218
|
-
self.register_readable(fd)
|
219
|
-
for fd in self._writable:
|
220
|
-
self.register_writable(fd)
|
221
|
-
|
222
|
-
def close(self) -> None:
|
223
|
-
self._kqueue.close() # type: ignore
|
224
|
-
self._kqueue = None
|
225
|
-
|
226
|
-
else:
|
227
|
-
KqueuePoller = None
|
228
|
-
|
229
|
-
|
230
|
-
def get_poller_impl() -> ta.Type[Poller]:
|
231
|
-
if (
|
232
|
-
(sys.platform == 'darwin' or sys.platform.startswith('freebsd')) and
|
233
|
-
hasattr(select, 'kqueue') and
|
234
|
-
KqueuePoller is not None
|
235
|
-
):
|
236
|
-
return KqueuePoller
|
237
|
-
elif hasattr(select, 'poll'):
|
238
|
-
return PollPoller
|
239
|
-
else:
|
240
|
-
return SelectPoller
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|