ominfra 0.0.0.dev129__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 +15 -0
- ominfra/pyremote/_runcommands.py +15 -0
- ominfra/scripts/journald2aws.py +112 -0
- ominfra/scripts/supervisor.py +1233 -484
- ominfra/supervisor/dispatchers.py +7 -6
- ominfra/supervisor/dispatchersimpl.py +3 -7
- ominfra/supervisor/groups.py +16 -1
- ominfra/supervisor/http.py +130 -0
- ominfra/supervisor/inject.py +44 -5
- ominfra/supervisor/io.py +39 -24
- ominfra/supervisor/processimpl.py +3 -4
- ominfra/supervisor/spawningimpl.py +2 -2
- ominfra/supervisor/supervisor.py +5 -2
- ominfra/supervisor/types.py +6 -56
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev130.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev130.dist-info}/RECORD +20 -20
- ominfra/supervisor/poller.py +0 -240
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev130.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev130.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev130.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev129.dist-info → ominfra-0.0.0.dev130.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,14 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
-
from .
|
2
|
+
from omlish.lite.fdio.handlers import FdIoHandler
|
3
|
+
|
3
4
|
from .types import ProcessOutputDispatcher
|
4
5
|
from .utils.collections import KeyedCollection
|
5
6
|
from .utils.ostypes import Fd
|
6
7
|
|
7
8
|
|
8
|
-
class Dispatchers(KeyedCollection[Fd,
|
9
|
-
def _key(self, v:
|
10
|
-
return v.fd
|
9
|
+
class Dispatchers(KeyedCollection[Fd, FdIoHandler]):
|
10
|
+
def _key(self, v: FdIoHandler) -> Fd:
|
11
|
+
return Fd(v.fd())
|
11
12
|
|
12
13
|
#
|
13
14
|
|
@@ -16,9 +17,9 @@ class Dispatchers(KeyedCollection[Fd, Dispatcher]):
|
|
16
17
|
# note that we *must* call readable() for every dispatcher, as it may have side effects for a given
|
17
18
|
# dispatcher (eg. call handle_listener_state_change for event listener processes)
|
18
19
|
if d.readable():
|
19
|
-
d.
|
20
|
+
d.on_readable()
|
20
21
|
if d.writable():
|
21
|
-
d.
|
22
|
+
d.on_writable()
|
22
23
|
|
23
24
|
#
|
24
25
|
|
@@ -60,7 +60,6 @@ class BaseProcessDispatcherImpl(ProcessDispatcher, abc.ABC):
|
|
60
60
|
def channel(self) -> str:
|
61
61
|
return self._channel
|
62
62
|
|
63
|
-
@property
|
64
63
|
def fd(self) -> Fd:
|
65
64
|
return self._fd
|
66
65
|
|
@@ -75,7 +74,7 @@ class BaseProcessDispatcherImpl(ProcessDispatcher, abc.ABC):
|
|
75
74
|
log.debug('fd %s closed, stopped monitoring %s', self._fd, self)
|
76
75
|
self._closed = True
|
77
76
|
|
78
|
-
def
|
77
|
+
def on_error(self, exc: ta.Optional[BaseException] = None) -> None:
|
79
78
|
nil, t, v, tbinfo = compact_traceback()
|
80
79
|
|
81
80
|
log.critical('uncaptured python exception, closing channel %s (%s:%s %s)', repr(self), t, v, tbinfo)
|
@@ -291,7 +290,7 @@ class ProcessOutputDispatcherImpl(BaseProcessDispatcherImpl, ProcessOutputDispat
|
|
291
290
|
return False
|
292
291
|
return True
|
293
292
|
|
294
|
-
def
|
293
|
+
def on_readable(self) -> None:
|
295
294
|
data = read_fd(self._fd)
|
296
295
|
self._output_buffer += data
|
297
296
|
self.record_output()
|
@@ -329,15 +328,12 @@ class ProcessInputDispatcherImpl(BaseProcessDispatcherImpl, ProcessInputDispatch
|
|
329
328
|
return True
|
330
329
|
return False
|
331
330
|
|
332
|
-
def readable(self) -> bool:
|
333
|
-
return False
|
334
|
-
|
335
331
|
def flush(self) -> None:
|
336
332
|
# other code depends on this raising EPIPE if the pipe is closed
|
337
333
|
sent = os.write(self._fd, as_bytes(self._input_buffer))
|
338
334
|
self._input_buffer = self._input_buffer[sent:]
|
339
335
|
|
340
|
-
def
|
336
|
+
def on_writable(self) -> None:
|
341
337
|
if self._input_buffer:
|
342
338
|
try:
|
343
339
|
self.flush()
|
ominfra/supervisor/groups.py
CHANGED
@@ -2,15 +2,20 @@
|
|
2
2
|
import typing as ta
|
3
3
|
|
4
4
|
from .configs import ProcessGroupConfig
|
5
|
+
from .dispatchers import Dispatchers
|
5
6
|
from .events import EventCallbacks
|
6
7
|
from .events import ProcessGroupAddedEvent
|
7
8
|
from .events import ProcessGroupRemovedEvent
|
9
|
+
from .types import HasDispatchers
|
8
10
|
from .types import Process
|
9
11
|
from .types import ProcessGroup
|
10
12
|
from .utils.collections import KeyedCollectionAccessors
|
11
13
|
|
12
14
|
|
13
|
-
class ProcessGroupManager(
|
15
|
+
class ProcessGroupManager(
|
16
|
+
KeyedCollectionAccessors[str, ProcessGroup],
|
17
|
+
HasDispatchers,
|
18
|
+
):
|
14
19
|
def __init__(
|
15
20
|
self,
|
16
21
|
*,
|
@@ -34,6 +39,16 @@ class ProcessGroupManager(KeyedCollectionAccessors[str, ProcessGroup]):
|
|
34
39
|
|
35
40
|
#
|
36
41
|
|
42
|
+
def get_dispatchers(self) -> Dispatchers:
|
43
|
+
return Dispatchers(
|
44
|
+
d
|
45
|
+
for g in self
|
46
|
+
for p in g
|
47
|
+
for d in p.get_dispatchers()
|
48
|
+
)
|
49
|
+
|
50
|
+
#
|
51
|
+
|
37
52
|
def add(self, group: ProcessGroup) -> None:
|
38
53
|
if (name := group.name) in self._by_name:
|
39
54
|
raise KeyError(f'Process group already exists: {name}')
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# ruff: noqa: U006 UP007
|
2
|
+
import json
|
3
|
+
import socket
|
4
|
+
import typing as ta
|
5
|
+
|
6
|
+
from omlish.lite.check import check_not_none
|
7
|
+
from omlish.lite.fdio.corohttp import CoroHttpServerConnectionFdIoHandler
|
8
|
+
from omlish.lite.fdio.handlers import SocketFdIoHandler
|
9
|
+
from omlish.lite.http.handlers import HttpHandler
|
10
|
+
from omlish.lite.http.handlers import HttpHandlerRequest
|
11
|
+
from omlish.lite.http.handlers import HttpHandlerResponse
|
12
|
+
from omlish.lite.json import JSON_PRETTY_KWARGS
|
13
|
+
from omlish.lite.socket import SocketAddress
|
14
|
+
|
15
|
+
from .dispatchers import Dispatchers
|
16
|
+
from .groups import ProcessGroupManager
|
17
|
+
from .types import HasDispatchers
|
18
|
+
|
19
|
+
|
20
|
+
##
|
21
|
+
|
22
|
+
|
23
|
+
class SocketServerFdIoHandler(SocketFdIoHandler):
|
24
|
+
def __init__(
|
25
|
+
self,
|
26
|
+
addr: SocketAddress,
|
27
|
+
on_connect: ta.Callable[[socket.socket, SocketAddress], None],
|
28
|
+
) -> None:
|
29
|
+
sock = socket.create_server(addr)
|
30
|
+
sock.setblocking(False)
|
31
|
+
|
32
|
+
super().__init__(addr, sock)
|
33
|
+
|
34
|
+
self._on_connect = on_connect
|
35
|
+
|
36
|
+
sock.listen(1)
|
37
|
+
|
38
|
+
def readable(self) -> bool:
|
39
|
+
return True
|
40
|
+
|
41
|
+
def on_readable(self) -> None:
|
42
|
+
cli_sock, cli_addr = check_not_none(self._sock).accept()
|
43
|
+
cli_sock.setblocking(False)
|
44
|
+
|
45
|
+
self._on_connect(cli_sock, cli_addr)
|
46
|
+
|
47
|
+
|
48
|
+
##
|
49
|
+
|
50
|
+
|
51
|
+
class HttpServer(HasDispatchers):
|
52
|
+
class Address(ta.NamedTuple):
|
53
|
+
a: SocketAddress
|
54
|
+
|
55
|
+
class Handler(ta.NamedTuple):
|
56
|
+
h: HttpHandler
|
57
|
+
|
58
|
+
def __init__(
|
59
|
+
self,
|
60
|
+
handler: Handler,
|
61
|
+
addr: Address = Address(('localhost', 8000)),
|
62
|
+
) -> None:
|
63
|
+
super().__init__()
|
64
|
+
|
65
|
+
self._handler = handler.h
|
66
|
+
self._addr = addr.a
|
67
|
+
|
68
|
+
self._server = SocketServerFdIoHandler(self._addr, self._on_connect)
|
69
|
+
|
70
|
+
self._conns: ta.List[CoroHttpServerConnectionFdIoHandler] = []
|
71
|
+
|
72
|
+
def get_dispatchers(self) -> Dispatchers:
|
73
|
+
l = []
|
74
|
+
for c in self._conns:
|
75
|
+
if not c.closed:
|
76
|
+
l.append(c)
|
77
|
+
self._conns = l
|
78
|
+
return Dispatchers([
|
79
|
+
self._server,
|
80
|
+
*l,
|
81
|
+
])
|
82
|
+
|
83
|
+
def _on_connect(self, sock: socket.socket, addr: SocketAddress) -> None:
|
84
|
+
conn = CoroHttpServerConnectionFdIoHandler(
|
85
|
+
addr,
|
86
|
+
sock,
|
87
|
+
self._handler,
|
88
|
+
)
|
89
|
+
|
90
|
+
self._conns.append(conn)
|
91
|
+
|
92
|
+
|
93
|
+
##
|
94
|
+
|
95
|
+
|
96
|
+
class SupervisorHttpHandler:
|
97
|
+
def __init__(
|
98
|
+
self,
|
99
|
+
*,
|
100
|
+
groups: ProcessGroupManager,
|
101
|
+
) -> None:
|
102
|
+
super().__init__()
|
103
|
+
|
104
|
+
self._groups = groups
|
105
|
+
|
106
|
+
def handle(self, req: HttpHandlerRequest) -> HttpHandlerResponse:
|
107
|
+
dct = {
|
108
|
+
'method': req.method,
|
109
|
+
'path': req.path,
|
110
|
+
'data': len(req.data or b''),
|
111
|
+
'groups': {
|
112
|
+
g.name: {
|
113
|
+
'processes': {
|
114
|
+
p.name: {
|
115
|
+
'pid': p.pid,
|
116
|
+
}
|
117
|
+
for p in g
|
118
|
+
},
|
119
|
+
}
|
120
|
+
for g in self._groups
|
121
|
+
},
|
122
|
+
}
|
123
|
+
|
124
|
+
return HttpHandlerResponse(
|
125
|
+
200,
|
126
|
+
data=json.dumps(dct, **JSON_PRETTY_KWARGS).encode('utf-8') + b'\n',
|
127
|
+
headers={
|
128
|
+
'Content-Type': 'application/json',
|
129
|
+
},
|
130
|
+
)
|
ominfra/supervisor/inject.py
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
+
import dataclasses as dc
|
2
3
|
import typing as ta
|
3
4
|
|
5
|
+
from omlish.lite.fdio.kqueue import KqueueFdIoPoller # noqa
|
6
|
+
from omlish.lite.fdio.pollers import FdIoPoller
|
7
|
+
from omlish.lite.fdio.pollers import PollFdIoPoller # noqa
|
8
|
+
from omlish.lite.fdio.pollers import SelectFdIoPoller
|
4
9
|
from omlish.lite.inject import InjectorBindingOrBindings
|
5
10
|
from omlish.lite.inject import InjectorBindings
|
6
11
|
from omlish.lite.inject import inj
|
@@ -12,9 +17,10 @@ from .events import EventCallbacks
|
|
12
17
|
from .groups import ProcessGroupManager
|
13
18
|
from .groupsimpl import ProcessFactory
|
14
19
|
from .groupsimpl import ProcessGroupImpl
|
20
|
+
from .http import HttpServer
|
21
|
+
from .http import SupervisorHttpHandler
|
22
|
+
from .io import HasDispatchersList
|
15
23
|
from .io import IoManager
|
16
|
-
from .poller import Poller
|
17
|
-
from .poller import get_poller_impl
|
18
24
|
from .process import PidHistory
|
19
25
|
from .processimpl import ProcessImpl
|
20
26
|
from .processimpl import ProcessSpawningFactory
|
@@ -31,12 +37,24 @@ from .spawningimpl import ProcessSpawningImpl
|
|
31
37
|
from .supervisor import ProcessGroupFactory
|
32
38
|
from .supervisor import Supervisor
|
33
39
|
from .supervisor import SupervisorStateManagerImpl
|
40
|
+
from .types import HasDispatchers
|
34
41
|
from .types import ServerEpoch
|
35
42
|
from .types import SupervisorStateManager
|
36
43
|
from .utils.signals import SignalReceiver
|
37
44
|
from .utils.users import get_user
|
38
45
|
|
39
46
|
|
47
|
+
@dc.dataclass(frozen=True)
|
48
|
+
class _FdIoPollerDaemonizeListener(DaemonizeListener):
|
49
|
+
_poller: FdIoPoller
|
50
|
+
|
51
|
+
def before_daemonize(self) -> None:
|
52
|
+
self._poller.close()
|
53
|
+
|
54
|
+
def after_daemonize(self) -> None:
|
55
|
+
self._poller.reopen()
|
56
|
+
|
57
|
+
|
40
58
|
def bind_server(
|
41
59
|
config: ServerConfig,
|
42
60
|
*,
|
@@ -46,22 +64,24 @@ def bind_server(
|
|
46
64
|
lst: ta.List[InjectorBindingOrBindings] = [
|
47
65
|
inj.bind(config),
|
48
66
|
|
67
|
+
inj.bind_array(DaemonizeListener),
|
49
68
|
inj.bind_array_type(DaemonizeListener, DaemonizeListeners),
|
50
69
|
|
51
70
|
inj.bind(SupervisorSetupImpl, singleton=True),
|
52
71
|
inj.bind(SupervisorSetup, to_key=SupervisorSetupImpl),
|
53
72
|
|
54
|
-
inj.bind(DaemonizeListener, array=True, to_key=Poller),
|
55
|
-
|
56
73
|
inj.bind(EventCallbacks, singleton=True),
|
57
74
|
|
58
75
|
inj.bind(SignalReceiver, singleton=True),
|
59
76
|
|
60
77
|
inj.bind(IoManager, singleton=True),
|
78
|
+
inj.bind_array(HasDispatchers),
|
79
|
+
inj.bind_array_type(HasDispatchers, HasDispatchersList),
|
61
80
|
|
62
81
|
inj.bind(SignalHandler, singleton=True),
|
63
82
|
|
64
83
|
inj.bind(ProcessGroupManager, singleton=True),
|
84
|
+
inj.bind(HasDispatchers, array=True, to_key=ProcessGroupManager),
|
65
85
|
|
66
86
|
inj.bind(Supervisor, singleton=True),
|
67
87
|
|
@@ -94,7 +114,26 @@ def bind_server(
|
|
94
114
|
|
95
115
|
#
|
96
116
|
|
97
|
-
|
117
|
+
poller_impl = next(filter(None, [
|
118
|
+
KqueueFdIoPoller,
|
119
|
+
PollFdIoPoller,
|
120
|
+
SelectFdIoPoller,
|
121
|
+
]))
|
122
|
+
lst.append(inj.bind(poller_impl, key=FdIoPoller, singleton=True))
|
123
|
+
inj.bind(_FdIoPollerDaemonizeListener, array=True, singleton=True)
|
124
|
+
|
125
|
+
#
|
126
|
+
|
127
|
+
def _provide_http_handler(s: SupervisorHttpHandler) -> HttpServer.Handler:
|
128
|
+
return HttpServer.Handler(s.handle)
|
129
|
+
|
130
|
+
lst.extend([
|
131
|
+
inj.bind(HttpServer, singleton=True, eager=True),
|
132
|
+
inj.bind(HasDispatchers, array=True, to_key=HttpServer),
|
133
|
+
|
134
|
+
inj.bind(SupervisorHttpHandler, singleton=True),
|
135
|
+
inj.bind(_provide_http_handler),
|
136
|
+
])
|
98
137
|
|
99
138
|
#
|
100
139
|
|
ominfra/supervisor/io.py
CHANGED
@@ -1,58 +1,71 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from omlish.lite.fdio.pollers import FdIoPoller
|
2
5
|
from omlish.lite.logs import log
|
3
6
|
|
4
7
|
from .dispatchers import Dispatchers
|
5
|
-
from .groups import ProcessGroupManager
|
6
|
-
from .poller import Poller
|
7
8
|
from .types import ExitNow
|
9
|
+
from .types import HasDispatchers
|
10
|
+
from .utils.ostypes import Fd
|
8
11
|
|
9
12
|
|
10
13
|
##
|
11
14
|
|
12
15
|
|
13
|
-
|
16
|
+
HasDispatchersList = ta.NewType('HasDispatchersList', ta.Sequence[HasDispatchers])
|
17
|
+
|
18
|
+
|
19
|
+
class IoManager(HasDispatchers):
|
14
20
|
def __init__(
|
15
21
|
self,
|
16
22
|
*,
|
17
|
-
poller:
|
18
|
-
|
23
|
+
poller: FdIoPoller,
|
24
|
+
has_dispatchers_list: HasDispatchersList,
|
19
25
|
) -> None:
|
20
26
|
super().__init__()
|
21
27
|
|
22
28
|
self._poller = poller
|
23
|
-
self.
|
29
|
+
self._has_dispatchers_list = has_dispatchers_list
|
24
30
|
|
25
31
|
def get_dispatchers(self) -> Dispatchers:
|
26
32
|
return Dispatchers(
|
27
33
|
d
|
28
|
-
for
|
29
|
-
for d in
|
34
|
+
for hd in self._has_dispatchers_list
|
35
|
+
for d in hd.get_dispatchers()
|
30
36
|
)
|
31
37
|
|
32
38
|
def poll(self) -> None:
|
33
39
|
dispatchers = self.get_dispatchers()
|
34
40
|
|
35
|
-
|
36
|
-
if
|
37
|
-
|
38
|
-
|
39
|
-
self._poller.register_writable(fd)
|
41
|
+
self._poller.update(
|
42
|
+
{fd for fd, d in dispatchers.items() if d.readable()},
|
43
|
+
{fd for fd, d in dispatchers.items() if d.writable()},
|
44
|
+
)
|
40
45
|
|
41
46
|
timeout = 1 # this cannot be fewer than the smallest TickEvent (5)
|
42
|
-
|
47
|
+
log.info(f'Polling: {timeout=}') # noqa
|
48
|
+
polled = self._poller.poll(timeout)
|
49
|
+
log.info(f'Polled: {polled=}') # noqa
|
50
|
+
if polled.msg is not None:
|
51
|
+
log.error(polled.msg)
|
52
|
+
if polled.exc is not None:
|
53
|
+
log.error('Poll exception: %r', polled.exc)
|
43
54
|
|
44
|
-
for
|
55
|
+
for r in polled.r:
|
56
|
+
fd = Fd(r)
|
45
57
|
if fd in dispatchers:
|
58
|
+
dispatcher = dispatchers[fd]
|
46
59
|
try:
|
47
|
-
dispatcher = dispatchers[fd]
|
48
60
|
log.debug('read event caused by %r', dispatcher)
|
49
|
-
dispatcher.
|
61
|
+
dispatcher.on_readable()
|
50
62
|
if not dispatcher.readable():
|
51
63
|
self._poller.unregister_readable(fd)
|
52
64
|
except ExitNow:
|
53
65
|
raise
|
54
|
-
except Exception: # noqa
|
55
|
-
|
66
|
+
except Exception as exc: # noqa
|
67
|
+
log.exception('Error in dispatcher: %r', dispatcher)
|
68
|
+
dispatcher.on_error(exc)
|
56
69
|
else:
|
57
70
|
# if the fd is not in combined map, we should unregister it. otherwise, it will be polled every
|
58
71
|
# time, which may cause 100% cpu usage
|
@@ -62,18 +75,20 @@ class IoManager:
|
|
62
75
|
except Exception: # noqa
|
63
76
|
pass
|
64
77
|
|
65
|
-
for
|
78
|
+
for w in polled.w:
|
79
|
+
fd = Fd(w)
|
66
80
|
if fd in dispatchers:
|
81
|
+
dispatcher = dispatchers[fd]
|
67
82
|
try:
|
68
|
-
dispatcher = dispatchers[fd]
|
69
83
|
log.debug('write event caused by %r', dispatcher)
|
70
|
-
dispatcher.
|
84
|
+
dispatcher.on_writable()
|
71
85
|
if not dispatcher.writable():
|
72
86
|
self._poller.unregister_writable(fd)
|
73
87
|
except ExitNow:
|
74
88
|
raise
|
75
|
-
except Exception: # noqa
|
76
|
-
|
89
|
+
except Exception as exc: # noqa
|
90
|
+
log.exception('Error in dispatcher: %r', dispatcher)
|
91
|
+
dispatcher.on_error(exc)
|
77
92
|
else:
|
78
93
|
log.debug('unexpected write event from fd %r', fd)
|
79
94
|
try:
|
@@ -378,6 +378,7 @@ class ProcessImpl(Process):
|
|
378
378
|
self._last_stop = now
|
379
379
|
|
380
380
|
if now > self._last_start:
|
381
|
+
log.info(f'{now - self._last_start=}') # noqa
|
381
382
|
too_quickly = now - self._last_start < self._config.startsecs
|
382
383
|
else:
|
383
384
|
too_quickly = False
|
@@ -447,8 +448,6 @@ class ProcessImpl(Process):
|
|
447
448
|
|
448
449
|
self._check_and_adjust_for_system_clock_rollback(now)
|
449
450
|
|
450
|
-
logger = log
|
451
|
-
|
452
451
|
if self._supervisor_states.state > SupervisorState.RESTARTING:
|
453
452
|
# dont start any processes if supervisor is shutting down
|
454
453
|
if state == ProcessState.EXITED:
|
@@ -480,14 +479,14 @@ class ProcessImpl(Process):
|
|
480
479
|
self.check_in_state(ProcessState.STARTING)
|
481
480
|
self.change_state(ProcessState.RUNNING)
|
482
481
|
msg = ('entered RUNNING state, process has stayed up for > than %s seconds (startsecs)' % self._config.startsecs) # noqa
|
483
|
-
|
482
|
+
log.info('success: %s %s', self.name, msg)
|
484
483
|
|
485
484
|
if state == ProcessState.BACKOFF:
|
486
485
|
if self._backoff > self._config.startretries:
|
487
486
|
# BACKOFF -> FATAL if the proc has exceeded its number of retries
|
488
487
|
self.give_up()
|
489
488
|
msg = ('entered FATAL state, too many start retries too quickly')
|
490
|
-
|
489
|
+
log.info('gave up: %s %s', self.name, msg)
|
491
490
|
|
492
491
|
elif state == ProcessState.STOPPING:
|
493
492
|
time_left = self._delay - now
|
@@ -7,6 +7,7 @@ import typing as ta
|
|
7
7
|
|
8
8
|
from omlish.lite.check import check_isinstance
|
9
9
|
from omlish.lite.check import check_not_none
|
10
|
+
from omlish.lite.fdio.handlers import FdIoHandler
|
10
11
|
from omlish.lite.typing import Func3
|
11
12
|
|
12
13
|
from .configs import ProcessConfig
|
@@ -29,7 +30,6 @@ from .process import PidHistory
|
|
29
30
|
from .spawning import ProcessSpawnError
|
30
31
|
from .spawning import ProcessSpawning
|
31
32
|
from .spawning import SpawnedProcess
|
32
|
-
from .types import Dispatcher
|
33
33
|
from .types import Process
|
34
34
|
from .types import ProcessGroup
|
35
35
|
from .types import ProcessInputDispatcher
|
@@ -200,7 +200,7 @@ class ProcessSpawningImpl(ProcessSpawning):
|
|
200
200
|
return exe, args
|
201
201
|
|
202
202
|
def _make_dispatchers(self, pipes: ProcessPipes) -> Dispatchers:
|
203
|
-
dispatchers: ta.List[
|
203
|
+
dispatchers: ta.List[FdIoHandler] = []
|
204
204
|
|
205
205
|
if pipes.stdout is not None:
|
206
206
|
dispatchers.append(check_isinstance(self._output_dispatcher_factory(
|
ominfra/supervisor/supervisor.py
CHANGED
@@ -5,6 +5,7 @@ import time
|
|
5
5
|
import typing as ta
|
6
6
|
|
7
7
|
from omlish.lite.check import check_isinstance
|
8
|
+
from omlish.lite.fdio.pollers import FdIoPoller
|
8
9
|
from omlish.lite.logs import log
|
9
10
|
from omlish.lite.typing import Func1
|
10
11
|
|
@@ -17,7 +18,6 @@ from .events import SupervisorStoppingEvent
|
|
17
18
|
from .groups import ProcessGroup
|
18
19
|
from .groups import ProcessGroupManager
|
19
20
|
from .io import IoManager
|
20
|
-
from .poller import Poller
|
21
21
|
from .process import PidHistory
|
22
22
|
from .setup import SupervisorSetup
|
23
23
|
from .signals import SignalHandler
|
@@ -66,7 +66,7 @@ class Supervisor:
|
|
66
66
|
self,
|
67
67
|
*,
|
68
68
|
config: ServerConfig,
|
69
|
-
poller:
|
69
|
+
poller: FdIoPoller,
|
70
70
|
process_groups: ProcessGroupManager,
|
71
71
|
signal_handler: SignalHandler,
|
72
72
|
event_callbacks: EventCallbacks,
|
@@ -182,7 +182,9 @@ class Supervisor:
|
|
182
182
|
#
|
183
183
|
|
184
184
|
def _run_once(self) -> None:
|
185
|
+
now = time.time()
|
185
186
|
self._poll()
|
187
|
+
log.info(f'Poll took {time.time() - now}') # noqa
|
186
188
|
self._reap()
|
187
189
|
self._signal_handler.handle_signals()
|
188
190
|
self._tick()
|
@@ -234,6 +236,7 @@ class Supervisor:
|
|
234
236
|
return
|
235
237
|
|
236
238
|
wp = waitpid()
|
239
|
+
log.info(f'Waited pid: {wp}') # noqa
|
237
240
|
if wp is None or not wp.pid:
|
238
241
|
return
|
239
242
|
|
ominfra/supervisor/types.py
CHANGED
@@ -3,12 +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
10
|
from .states import ProcessState
|
9
11
|
from .states import SupervisorState
|
10
12
|
from .utils.collections import KeyedCollectionAccessors
|
11
|
-
from .utils.ostypes import Fd
|
12
13
|
from .utils.ostypes import Pid
|
13
14
|
from .utils.ostypes import Rc
|
14
15
|
|
@@ -61,69 +62,18 @@ class SupervisorStateManager(abc.ABC):
|
|
61
62
|
##
|
62
63
|
|
63
64
|
|
64
|
-
class
|
65
|
-
@property
|
65
|
+
class HasDispatchers(abc.ABC):
|
66
66
|
@abc.abstractmethod
|
67
|
-
def
|
67
|
+
def get_dispatchers(self) -> 'Dispatchers':
|
68
68
|
raise NotImplementedError
|
69
69
|
|
70
|
-
@property
|
71
|
-
@abc.abstractmethod
|
72
|
-
def fd(self) -> Fd:
|
73
|
-
raise NotImplementedError
|
74
70
|
|
71
|
+
class ProcessDispatcher(FdIoHandler, abc.ABC):
|
75
72
|
@property
|
76
73
|
@abc.abstractmethod
|
77
|
-
def
|
78
|
-
raise NotImplementedError
|
79
|
-
|
80
|
-
#
|
81
|
-
|
82
|
-
@abc.abstractmethod
|
83
|
-
def close(self) -> None:
|
84
|
-
raise NotImplementedError
|
85
|
-
|
86
|
-
@abc.abstractmethod
|
87
|
-
def handle_error(self) -> None:
|
88
|
-
raise NotImplementedError
|
89
|
-
|
90
|
-
#
|
91
|
-
|
92
|
-
@abc.abstractmethod
|
93
|
-
def readable(self) -> bool:
|
94
|
-
raise NotImplementedError
|
95
|
-
|
96
|
-
@abc.abstractmethod
|
97
|
-
def writable(self) -> bool:
|
98
|
-
raise NotImplementedError
|
99
|
-
|
100
|
-
#
|
101
|
-
|
102
|
-
def handle_read_event(self) -> None:
|
103
|
-
raise TypeError
|
104
|
-
|
105
|
-
def handle_write_event(self) -> None:
|
106
|
-
raise TypeError
|
107
|
-
|
108
|
-
#
|
109
|
-
|
110
|
-
def handle_connect(self) -> None:
|
111
|
-
raise TypeError
|
112
|
-
|
113
|
-
def handle_close(self) -> None:
|
114
|
-
raise TypeError
|
115
|
-
|
116
|
-
def handle_accepted(self, sock, addr) -> None:
|
117
|
-
raise TypeError
|
118
|
-
|
119
|
-
|
120
|
-
class HasDispatchers(abc.ABC):
|
121
|
-
@abc.abstractmethod
|
122
|
-
def get_dispatchers(self) -> 'Dispatchers':
|
74
|
+
def channel(self) -> str:
|
123
75
|
raise NotImplementedError
|
124
76
|
|
125
|
-
|
126
|
-
class ProcessDispatcher(Dispatcher, abc.ABC):
|
127
77
|
@property
|
128
78
|
@abc.abstractmethod
|
129
79
|
def process(self) -> 'Process':
|
@@ -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"
|