ominfra 0.0.0.dev128__py3-none-any.whl → 0.0.0.dev129__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 +24 -0
- ominfra/pyremote/_runcommands.py +24 -0
- ominfra/scripts/journald2aws.py +24 -0
- ominfra/scripts/supervisor.py +543 -440
- ominfra/supervisor/dispatchers.py +3 -3
- ominfra/supervisor/dispatchersimpl.py +17 -11
- ominfra/supervisor/groupsimpl.py +2 -2
- ominfra/supervisor/inject.py +17 -12
- ominfra/supervisor/io.py +82 -0
- ominfra/supervisor/main.py +5 -6
- ominfra/supervisor/processimpl.py +7 -14
- ominfra/supervisor/signals.py +66 -0
- ominfra/supervisor/spawningimpl.py +9 -9
- ominfra/supervisor/supervisor.py +65 -135
- ominfra/supervisor/types.py +38 -25
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev129.dist-info}/METADATA +3 -3
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev129.dist-info}/RECORD +21 -20
- ominfra/supervisor/context.py +0 -80
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev129.dist-info}/LICENSE +0 -0
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev129.dist-info}/WHEEL +0 -0
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev129.dist-info}/entry_points.txt +0 -0
- {ominfra-0.0.0.dev128.dist-info → ominfra-0.0.0.dev129.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
# ruff: noqa: UP006 UP007
|
2
2
|
from .types import Dispatcher
|
3
|
-
from .types import
|
3
|
+
from .types import ProcessOutputDispatcher
|
4
4
|
from .utils.collections import KeyedCollection
|
5
5
|
from .utils.ostypes import Fd
|
6
6
|
|
@@ -24,10 +24,10 @@ class Dispatchers(KeyedCollection[Fd, Dispatcher]):
|
|
24
24
|
|
25
25
|
def remove_logs(self) -> None:
|
26
26
|
for d in self:
|
27
|
-
if isinstance(d,
|
27
|
+
if isinstance(d, ProcessOutputDispatcher):
|
28
28
|
d.remove_logs()
|
29
29
|
|
30
30
|
def reopen_logs(self) -> None:
|
31
31
|
for d in self:
|
32
|
-
if isinstance(d,
|
32
|
+
if isinstance(d, ProcessOutputDispatcher):
|
33
33
|
d.reopen_logs()
|
@@ -8,14 +8,15 @@ import typing as ta
|
|
8
8
|
from omlish.lite.logs import log
|
9
9
|
|
10
10
|
from .configs import ProcessConfig
|
11
|
+
from .configs import ServerConfig
|
11
12
|
from .events import EventCallbacks
|
12
13
|
from .events import ProcessCommunicationEvent
|
13
14
|
from .events import ProcessLogStderrEvent
|
14
15
|
from .events import ProcessLogStdoutEvent
|
15
|
-
from .types import Dispatcher
|
16
|
-
from .types import InputDispatcher
|
17
|
-
from .types import OutputDispatcher
|
18
16
|
from .types import Process
|
17
|
+
from .types import ProcessDispatcher
|
18
|
+
from .types import ProcessInputDispatcher
|
19
|
+
from .types import ProcessOutputDispatcher
|
19
20
|
from .utils.diag import compact_traceback
|
20
21
|
from .utils.fds import read_fd
|
21
22
|
from .utils.ostypes import Fd
|
@@ -24,7 +25,7 @@ from .utils.strings import find_prefix_at_end
|
|
24
25
|
from .utils.strings import strip_escapes
|
25
26
|
|
26
27
|
|
27
|
-
class
|
28
|
+
class BaseProcessDispatcherImpl(ProcessDispatcher, abc.ABC):
|
28
29
|
def __init__(
|
29
30
|
self,
|
30
31
|
process: Process,
|
@@ -32,6 +33,7 @@ class BaseDispatcherImpl(Dispatcher, abc.ABC):
|
|
32
33
|
fd: Fd,
|
33
34
|
*,
|
34
35
|
event_callbacks: EventCallbacks,
|
36
|
+
server_config: ServerConfig,
|
35
37
|
) -> None:
|
36
38
|
super().__init__()
|
37
39
|
|
@@ -39,6 +41,7 @@ class BaseDispatcherImpl(Dispatcher, abc.ABC):
|
|
39
41
|
self._channel = channel # 'stderr' or 'stdout'
|
40
42
|
self._fd = fd
|
41
43
|
self._event_callbacks = event_callbacks
|
44
|
+
self._server_config = server_config
|
42
45
|
|
43
46
|
self._closed = False # True if close() has been called
|
44
47
|
|
@@ -79,7 +82,7 @@ class BaseDispatcherImpl(Dispatcher, abc.ABC):
|
|
79
82
|
self.close()
|
80
83
|
|
81
84
|
|
82
|
-
class
|
85
|
+
class ProcessOutputDispatcherImpl(BaseProcessDispatcherImpl, ProcessOutputDispatcher):
|
83
86
|
"""
|
84
87
|
Dispatcher for one channel (stdout or stderr) of one process. Serves several purposes:
|
85
88
|
|
@@ -95,12 +98,14 @@ class OutputDispatcherImpl(BaseDispatcherImpl, OutputDispatcher):
|
|
95
98
|
fd: Fd,
|
96
99
|
*,
|
97
100
|
event_callbacks: EventCallbacks,
|
101
|
+
server_config: ServerConfig,
|
98
102
|
) -> None:
|
99
103
|
super().__init__(
|
100
104
|
process,
|
101
105
|
event_type.channel,
|
102
106
|
fd,
|
103
107
|
event_callbacks=event_callbacks,
|
108
|
+
server_config=server_config,
|
104
109
|
)
|
105
110
|
|
106
111
|
self._event_type = event_type
|
@@ -124,11 +129,10 @@ class OutputDispatcherImpl(BaseDispatcherImpl, OutputDispatcher):
|
|
124
129
|
|
125
130
|
self._main_log_level = logging.DEBUG
|
126
131
|
|
127
|
-
self._log_to_main_log =
|
132
|
+
self._log_to_main_log = self._server_config.loglevel <= self._main_log_level
|
128
133
|
|
129
|
-
|
130
|
-
self.
|
131
|
-
self._stderr_events_enabled = config.stderr.events_enabled
|
134
|
+
self._stdout_events_enabled = self._process.config.stdout.events_enabled
|
135
|
+
self._stderr_events_enabled = self._process.config.stderr.events_enabled
|
132
136
|
|
133
137
|
_child_log: ta.Optional[logging.Logger] = None # the current logger (normal_log or capture_log)
|
134
138
|
_normal_log: ta.Optional[logging.Logger] = None # the "normal" (non-capture) logger
|
@@ -199,7 +203,7 @@ class OutputDispatcherImpl(BaseDispatcherImpl, OutputDispatcher):
|
|
199
203
|
if not data:
|
200
204
|
return
|
201
205
|
|
202
|
-
if self.
|
206
|
+
if self._server_config.strip_ansi:
|
203
207
|
data = strip_escapes(as_bytes(data))
|
204
208
|
|
205
209
|
if self._child_log:
|
@@ -297,7 +301,7 @@ class OutputDispatcherImpl(BaseDispatcherImpl, OutputDispatcher):
|
|
297
301
|
self.close()
|
298
302
|
|
299
303
|
|
300
|
-
class
|
304
|
+
class ProcessInputDispatcherImpl(BaseProcessDispatcherImpl, ProcessInputDispatcher):
|
301
305
|
def __init__(
|
302
306
|
self,
|
303
307
|
process: Process,
|
@@ -305,12 +309,14 @@ class InputDispatcherImpl(BaseDispatcherImpl, InputDispatcher):
|
|
305
309
|
fd: Fd,
|
306
310
|
*,
|
307
311
|
event_callbacks: EventCallbacks,
|
312
|
+
server_config: ServerConfig,
|
308
313
|
) -> None:
|
309
314
|
super().__init__(
|
310
315
|
process,
|
311
316
|
channel,
|
312
317
|
fd,
|
313
318
|
event_callbacks=event_callbacks,
|
319
|
+
server_config=server_config,
|
314
320
|
)
|
315
321
|
|
316
322
|
self._input_buffer = b''
|
ominfra/supervisor/groupsimpl.py
CHANGED
@@ -61,7 +61,7 @@ class ProcessGroupImpl(ProcessGroup):
|
|
61
61
|
#
|
62
62
|
|
63
63
|
def get_unstopped_processes(self) -> ta.List[Process]:
|
64
|
-
return [x for x in self if not x.
|
64
|
+
return [x for x in self if not x.state.stopped]
|
65
65
|
|
66
66
|
def stop_all(self) -> None:
|
67
67
|
processes = list(self._by_name.values())
|
@@ -69,7 +69,7 @@ class ProcessGroupImpl(ProcessGroup):
|
|
69
69
|
processes.reverse() # stop in desc priority order
|
70
70
|
|
71
71
|
for proc in processes:
|
72
|
-
state = proc.
|
72
|
+
state = proc.state
|
73
73
|
if state == ProcessState.RUNNING:
|
74
74
|
# RUNNING -> STOPPING
|
75
75
|
proc.stop()
|
ominfra/supervisor/inject.py
CHANGED
@@ -6,13 +6,13 @@ from omlish.lite.inject import InjectorBindings
|
|
6
6
|
from omlish.lite.inject import inj
|
7
7
|
|
8
8
|
from .configs import ServerConfig
|
9
|
-
from .
|
10
|
-
from .dispatchersimpl import
|
11
|
-
from .dispatchersimpl import OutputDispatcherImpl
|
9
|
+
from .dispatchersimpl import ProcessInputDispatcherImpl
|
10
|
+
from .dispatchersimpl import ProcessOutputDispatcherImpl
|
12
11
|
from .events import EventCallbacks
|
13
12
|
from .groups import ProcessGroupManager
|
14
13
|
from .groupsimpl import ProcessFactory
|
15
14
|
from .groupsimpl import ProcessGroupImpl
|
15
|
+
from .io import IoManager
|
16
16
|
from .poller import Poller
|
17
17
|
from .poller import get_poller_impl
|
18
18
|
from .process import PidHistory
|
@@ -23,15 +23,16 @@ from .setup import DaemonizeListeners
|
|
23
23
|
from .setup import SupervisorUser
|
24
24
|
from .setupimpl import SupervisorSetup
|
25
25
|
from .setupimpl import SupervisorSetupImpl
|
26
|
+
from .signals import SignalHandler
|
26
27
|
from .spawningimpl import InheritedFds
|
27
|
-
from .spawningimpl import
|
28
|
-
from .spawningimpl import
|
28
|
+
from .spawningimpl import ProcessInputDispatcherFactory
|
29
|
+
from .spawningimpl import ProcessOutputDispatcherFactory
|
29
30
|
from .spawningimpl import ProcessSpawningImpl
|
30
31
|
from .supervisor import ProcessGroupFactory
|
31
|
-
from .supervisor import SignalHandler
|
32
32
|
from .supervisor import Supervisor
|
33
|
-
from .
|
33
|
+
from .supervisor import SupervisorStateManagerImpl
|
34
34
|
from .types import ServerEpoch
|
35
|
+
from .types import SupervisorStateManager
|
35
36
|
from .utils.signals import SignalReceiver
|
36
37
|
from .utils.users import get_user
|
37
38
|
|
@@ -52,17 +53,21 @@ def bind_server(
|
|
52
53
|
|
53
54
|
inj.bind(DaemonizeListener, array=True, to_key=Poller),
|
54
55
|
|
55
|
-
inj.bind(ServerContextImpl, singleton=True),
|
56
|
-
inj.bind(ServerContext, to_key=ServerContextImpl),
|
57
|
-
|
58
56
|
inj.bind(EventCallbacks, singleton=True),
|
59
57
|
|
60
58
|
inj.bind(SignalReceiver, singleton=True),
|
61
59
|
|
60
|
+
inj.bind(IoManager, singleton=True),
|
61
|
+
|
62
62
|
inj.bind(SignalHandler, singleton=True),
|
63
|
+
|
63
64
|
inj.bind(ProcessGroupManager, singleton=True),
|
65
|
+
|
64
66
|
inj.bind(Supervisor, singleton=True),
|
65
67
|
|
68
|
+
inj.bind(SupervisorStateManagerImpl, singleton=True),
|
69
|
+
inj.bind(SupervisorStateManager, to_key=SupervisorStateManagerImpl),
|
70
|
+
|
66
71
|
inj.bind(PidHistory()),
|
67
72
|
|
68
73
|
inj.bind_factory(ProcessGroupImpl, ProcessGroupFactory),
|
@@ -70,8 +75,8 @@ def bind_server(
|
|
70
75
|
|
71
76
|
inj.bind_factory(ProcessSpawningImpl, ProcessSpawningFactory),
|
72
77
|
|
73
|
-
inj.bind_factory(
|
74
|
-
inj.bind_factory(
|
78
|
+
inj.bind_factory(ProcessOutputDispatcherImpl, ProcessOutputDispatcherFactory),
|
79
|
+
inj.bind_factory(ProcessInputDispatcherImpl, ProcessInputDispatcherFactory),
|
75
80
|
]
|
76
81
|
|
77
82
|
#
|
ominfra/supervisor/io.py
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
from omlish.lite.logs import log
|
3
|
+
|
4
|
+
from .dispatchers import Dispatchers
|
5
|
+
from .groups import ProcessGroupManager
|
6
|
+
from .poller import Poller
|
7
|
+
from .types import ExitNow
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
|
12
|
+
|
13
|
+
class IoManager:
|
14
|
+
def __init__(
|
15
|
+
self,
|
16
|
+
*,
|
17
|
+
poller: Poller,
|
18
|
+
process_groups: ProcessGroupManager,
|
19
|
+
) -> None:
|
20
|
+
super().__init__()
|
21
|
+
|
22
|
+
self._poller = poller
|
23
|
+
self._process_groups = process_groups
|
24
|
+
|
25
|
+
def get_dispatchers(self) -> Dispatchers:
|
26
|
+
return Dispatchers(
|
27
|
+
d
|
28
|
+
for p in self._process_groups.all_processes()
|
29
|
+
for d in p.get_dispatchers()
|
30
|
+
)
|
31
|
+
|
32
|
+
def poll(self) -> None:
|
33
|
+
dispatchers = self.get_dispatchers()
|
34
|
+
|
35
|
+
for fd, dispatcher in dispatchers.items():
|
36
|
+
if dispatcher.readable():
|
37
|
+
self._poller.register_readable(fd)
|
38
|
+
if dispatcher.writable():
|
39
|
+
self._poller.register_writable(fd)
|
40
|
+
|
41
|
+
timeout = 1 # this cannot be fewer than the smallest TickEvent (5)
|
42
|
+
r, w = self._poller.poll(timeout)
|
43
|
+
|
44
|
+
for fd in r:
|
45
|
+
if fd in dispatchers:
|
46
|
+
try:
|
47
|
+
dispatcher = dispatchers[fd]
|
48
|
+
log.debug('read event caused by %r', dispatcher)
|
49
|
+
dispatcher.handle_read_event()
|
50
|
+
if not dispatcher.readable():
|
51
|
+
self._poller.unregister_readable(fd)
|
52
|
+
except ExitNow:
|
53
|
+
raise
|
54
|
+
except Exception: # noqa
|
55
|
+
dispatchers[fd].handle_error()
|
56
|
+
else:
|
57
|
+
# if the fd is not in combined map, we should unregister it. otherwise, it will be polled every
|
58
|
+
# time, which may cause 100% cpu usage
|
59
|
+
log.debug('unexpected read event from fd %r', fd)
|
60
|
+
try:
|
61
|
+
self._poller.unregister_readable(fd)
|
62
|
+
except Exception: # noqa
|
63
|
+
pass
|
64
|
+
|
65
|
+
for fd in w:
|
66
|
+
if fd in dispatchers:
|
67
|
+
try:
|
68
|
+
dispatcher = dispatchers[fd]
|
69
|
+
log.debug('write event caused by %r', dispatcher)
|
70
|
+
dispatcher.handle_write_event()
|
71
|
+
if not dispatcher.writable():
|
72
|
+
self._poller.unregister_writable(fd)
|
73
|
+
except ExitNow:
|
74
|
+
raise
|
75
|
+
except Exception: # noqa
|
76
|
+
dispatchers[fd].handle_error()
|
77
|
+
else:
|
78
|
+
log.debug('unexpected write event from fd %r', fd)
|
79
|
+
try:
|
80
|
+
self._poller.unregister_writable(fd)
|
81
|
+
except Exception: # noqa
|
82
|
+
pass
|
ominfra/supervisor/main.py
CHANGED
@@ -37,17 +37,17 @@ from omlish.lite.http.coroserver import CoroHttpServer
|
|
37
37
|
from omlish.lite.inject import inj
|
38
38
|
from omlish.lite.journald import journald_log_handler_factory
|
39
39
|
from omlish.lite.logs import configure_standard_logging
|
40
|
+
from omlish.lite.runtime import is_debugger_attached
|
40
41
|
|
41
42
|
from ..configs import read_config_file
|
42
43
|
from .configs import ServerConfig
|
43
44
|
from .configs import prepare_server_config
|
44
|
-
from .context import ServerContextImpl
|
45
|
-
from .context import ServerEpoch
|
46
45
|
from .inject import bind_server
|
47
46
|
from .spawningimpl import InheritedFds
|
48
47
|
from .states import SupervisorState
|
49
|
-
from .supervisor import ExitNow
|
50
48
|
from .supervisor import Supervisor
|
49
|
+
from .types import ExitNow
|
50
|
+
from .types import ServerEpoch
|
51
51
|
from .utils.fds import get_open_fds
|
52
52
|
|
53
53
|
|
@@ -79,7 +79,7 @@ def main(
|
|
79
79
|
if not no_logging:
|
80
80
|
configure_standard_logging(
|
81
81
|
'INFO',
|
82
|
-
handler_factory=journald_log_handler_factory if not args.no_journald else None,
|
82
|
+
handler_factory=journald_log_handler_factory if not (args.no_journald or is_debugger_attached()) else None,
|
83
83
|
)
|
84
84
|
|
85
85
|
#
|
@@ -102,7 +102,6 @@ def main(
|
|
102
102
|
inherited_fds=inherited_fds,
|
103
103
|
))
|
104
104
|
|
105
|
-
context = injector[ServerContextImpl]
|
106
105
|
supervisor = injector[Supervisor]
|
107
106
|
|
108
107
|
try:
|
@@ -110,7 +109,7 @@ def main(
|
|
110
109
|
except ExitNow:
|
111
110
|
pass
|
112
111
|
|
113
|
-
if
|
112
|
+
if supervisor.state < SupervisorState.RESTARTING:
|
114
113
|
break
|
115
114
|
|
116
115
|
|
@@ -22,10 +22,10 @@ from .spawning import ProcessSpawnError
|
|
22
22
|
from .spawning import ProcessSpawning
|
23
23
|
from .states import ProcessState
|
24
24
|
from .states import SupervisorState
|
25
|
-
from .types import InputDispatcher
|
26
25
|
from .types import Process
|
27
26
|
from .types import ProcessGroup
|
28
|
-
from .types import
|
27
|
+
from .types import ProcessInputDispatcher
|
28
|
+
from .types import SupervisorStateManager
|
29
29
|
from .utils.os import decode_wait_status
|
30
30
|
from .utils.ostypes import Pid
|
31
31
|
from .utils.ostypes import Rc
|
@@ -47,7 +47,7 @@ class ProcessImpl(Process):
|
|
47
47
|
config: ProcessConfig,
|
48
48
|
group: ProcessGroup,
|
49
49
|
*,
|
50
|
-
|
50
|
+
supervisor_states: SupervisorStateManager,
|
51
51
|
event_callbacks: EventCallbacks,
|
52
52
|
process_spawning_factory: ProcessSpawningFactory,
|
53
53
|
) -> None:
|
@@ -56,7 +56,7 @@ class ProcessImpl(Process):
|
|
56
56
|
self._config = config
|
57
57
|
self._group = group
|
58
58
|
|
59
|
-
self.
|
59
|
+
self._supervisor_states = supervisor_states
|
60
60
|
self._event_callbacks = event_callbacks
|
61
61
|
|
62
62
|
self._spawning = process_spawning_factory(self)
|
@@ -87,7 +87,7 @@ class ProcessImpl(Process):
|
|
87
87
|
#
|
88
88
|
|
89
89
|
def __repr__(self) -> str:
|
90
|
-
return f'<Subprocess at {id(self)} with name {self._config.name} in state {self.
|
90
|
+
return f'<Subprocess at {id(self)} with name {self._config.name} in state {self._state.name}>'
|
91
91
|
|
92
92
|
#
|
93
93
|
|
@@ -109,10 +109,6 @@ class ProcessImpl(Process):
|
|
109
109
|
|
110
110
|
#
|
111
111
|
|
112
|
-
@property
|
113
|
-
def context(self) -> ServerContext:
|
114
|
-
return self._context
|
115
|
-
|
116
112
|
@property
|
117
113
|
def state(self) -> ProcessState:
|
118
114
|
return self._state
|
@@ -175,7 +171,7 @@ class ProcessImpl(Process):
|
|
175
171
|
if stdin_fd is None:
|
176
172
|
raise OSError(errno.EPIPE, 'Process has no stdin channel')
|
177
173
|
|
178
|
-
dispatcher = check_isinstance(self._dispatchers[stdin_fd],
|
174
|
+
dispatcher = check_isinstance(self._dispatchers[stdin_fd], ProcessInputDispatcher)
|
179
175
|
if dispatcher.closed:
|
180
176
|
raise OSError(errno.EPIPE, "Process' stdin channel is closed")
|
181
177
|
|
@@ -445,9 +441,6 @@ class ProcessImpl(Process):
|
|
445
441
|
self._pipes = ProcessPipes()
|
446
442
|
self._dispatchers = Dispatchers([])
|
447
443
|
|
448
|
-
def get_state(self) -> ProcessState:
|
449
|
-
return self._state
|
450
|
-
|
451
444
|
def transition(self) -> None:
|
452
445
|
now = time.time()
|
453
446
|
state = self._state
|
@@ -456,7 +449,7 @@ class ProcessImpl(Process):
|
|
456
449
|
|
457
450
|
logger = log
|
458
451
|
|
459
|
-
if self.
|
452
|
+
if self._supervisor_states.state > SupervisorState.RESTARTING:
|
460
453
|
# dont start any processes if supervisor is shutting down
|
461
454
|
if state == ProcessState.EXITED:
|
462
455
|
if self._config.autorestart:
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
import signal
|
3
|
+
|
4
|
+
from omlish.lite.logs import log
|
5
|
+
|
6
|
+
from .groups import ProcessGroupManager
|
7
|
+
from .states import SupervisorState
|
8
|
+
from .types import ProcessOutputDispatcher
|
9
|
+
from .types import SupervisorStateManager
|
10
|
+
from .utils.signals import SignalReceiver
|
11
|
+
from .utils.signals import sig_name
|
12
|
+
|
13
|
+
|
14
|
+
class SignalHandler:
|
15
|
+
def __init__(
|
16
|
+
self,
|
17
|
+
*,
|
18
|
+
states: SupervisorStateManager,
|
19
|
+
signal_receiver: SignalReceiver,
|
20
|
+
process_groups: ProcessGroupManager,
|
21
|
+
) -> None:
|
22
|
+
super().__init__()
|
23
|
+
|
24
|
+
self._states = states
|
25
|
+
self._signal_receiver = signal_receiver
|
26
|
+
self._process_groups = process_groups
|
27
|
+
|
28
|
+
def set_signals(self) -> None:
|
29
|
+
self._signal_receiver.install(
|
30
|
+
signal.SIGTERM,
|
31
|
+
signal.SIGINT,
|
32
|
+
signal.SIGQUIT,
|
33
|
+
signal.SIGHUP,
|
34
|
+
signal.SIGCHLD,
|
35
|
+
signal.SIGUSR2,
|
36
|
+
)
|
37
|
+
|
38
|
+
def handle_signals(self) -> None:
|
39
|
+
sig = self._signal_receiver.get_signal()
|
40
|
+
if not sig:
|
41
|
+
return
|
42
|
+
|
43
|
+
if sig in (signal.SIGTERM, signal.SIGINT, signal.SIGQUIT):
|
44
|
+
log.warning('received %s indicating exit request', sig_name(sig))
|
45
|
+
self._states.set_state(SupervisorState.SHUTDOWN)
|
46
|
+
|
47
|
+
elif sig == signal.SIGHUP:
|
48
|
+
if self._states.state == SupervisorState.SHUTDOWN:
|
49
|
+
log.warning('ignored %s indicating restart request (shutdown in progress)', sig_name(sig)) # noqa
|
50
|
+
else:
|
51
|
+
log.warning('received %s indicating restart request', sig_name(sig)) # noqa
|
52
|
+
self._states.set_state(SupervisorState.RESTARTING)
|
53
|
+
|
54
|
+
elif sig == signal.SIGCHLD:
|
55
|
+
log.debug('received %s indicating a child quit', sig_name(sig))
|
56
|
+
|
57
|
+
elif sig == signal.SIGUSR2:
|
58
|
+
log.info('received %s indicating log reopen request', sig_name(sig))
|
59
|
+
|
60
|
+
for p in self._process_groups.all_processes():
|
61
|
+
for d in p.get_dispatchers():
|
62
|
+
if isinstance(d, ProcessOutputDispatcher):
|
63
|
+
d.reopen_logs()
|
64
|
+
|
65
|
+
else:
|
66
|
+
log.debug('received %s indicating nothing', sig_name(sig))
|
@@ -30,10 +30,10 @@ from .spawning import ProcessSpawnError
|
|
30
30
|
from .spawning import ProcessSpawning
|
31
31
|
from .spawning import SpawnedProcess
|
32
32
|
from .types import Dispatcher
|
33
|
-
from .types import InputDispatcher
|
34
|
-
from .types import OutputDispatcher
|
35
33
|
from .types import Process
|
36
34
|
from .types import ProcessGroup
|
35
|
+
from .types import ProcessInputDispatcher
|
36
|
+
from .types import ProcessOutputDispatcher
|
37
37
|
from .utils.diag import compact_traceback
|
38
38
|
from .utils.fds import close_fd
|
39
39
|
from .utils.fs import get_path
|
@@ -44,11 +44,11 @@ from .utils.ostypes import Rc
|
|
44
44
|
from .utils.strings import as_bytes
|
45
45
|
|
46
46
|
|
47
|
-
class
|
47
|
+
class ProcessOutputDispatcherFactory(Func3[Process, ta.Type[ProcessCommunicationEvent], Fd, ProcessOutputDispatcher]):
|
48
48
|
pass
|
49
49
|
|
50
50
|
|
51
|
-
class
|
51
|
+
class ProcessInputDispatcherFactory(Func3[Process, str, Fd, ProcessInputDispatcher]):
|
52
52
|
pass
|
53
53
|
|
54
54
|
|
@@ -66,8 +66,8 @@ class ProcessSpawningImpl(ProcessSpawning):
|
|
66
66
|
server_config: ServerConfig,
|
67
67
|
pid_history: PidHistory,
|
68
68
|
|
69
|
-
output_dispatcher_factory:
|
70
|
-
input_dispatcher_factory:
|
69
|
+
output_dispatcher_factory: ProcessOutputDispatcherFactory,
|
70
|
+
input_dispatcher_factory: ProcessInputDispatcherFactory,
|
71
71
|
|
72
72
|
inherited_fds: ta.Optional[InheritedFds] = None,
|
73
73
|
) -> None:
|
@@ -207,21 +207,21 @@ class ProcessSpawningImpl(ProcessSpawning):
|
|
207
207
|
self.process,
|
208
208
|
ProcessCommunicationStdoutEvent,
|
209
209
|
pipes.stdout,
|
210
|
-
),
|
210
|
+
), ProcessOutputDispatcher))
|
211
211
|
|
212
212
|
if pipes.stderr is not None:
|
213
213
|
dispatchers.append(check_isinstance(self._output_dispatcher_factory(
|
214
214
|
self.process,
|
215
215
|
ProcessCommunicationStderrEvent,
|
216
216
|
pipes.stderr,
|
217
|
-
),
|
217
|
+
), ProcessOutputDispatcher))
|
218
218
|
|
219
219
|
if pipes.stdin is not None:
|
220
220
|
dispatchers.append(check_isinstance(self._input_dispatcher_factory(
|
221
221
|
self.process,
|
222
222
|
'stdin',
|
223
223
|
pipes.stdin,
|
224
|
-
),
|
224
|
+
), ProcessInputDispatcher))
|
225
225
|
|
226
226
|
return Dispatchers(dispatchers)
|
227
227
|
|