ominfra 0.0.0.dev128__py3-none-any.whl → 0.0.0.dev129__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|