Skip to content

Commit 3338fd3

Browse files
author
Michael Hammann
committed
fix: reimplement depends_on flag using dicts
2 parents 18a7a8d + d9b812c commit 3338fd3

File tree

5 files changed

+151
-301
lines changed

5 files changed

+151
-301
lines changed

CHANGELOG.md

Lines changed: 0 additions & 29 deletions
This file was deleted.

supervisor/options.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -932,13 +932,6 @@ def get(section, opt, *args, **kwargs):
932932
serverurl = get(section, 'serverurl', None)
933933
if serverurl and serverurl.strip().upper() == 'AUTO':
934934
serverurl = None
935-
runningregex = get(section, 'runningregex', None)
936-
if runningregex:
937-
try:
938-
runningregex = re.compile(r'.*'+ runningregex)
939-
except Exception as e:
940-
raise ValueError(
941-
f"program section {section} has invalid runningregex value. Error {e}")
942935
depends_on = get(section, 'depends_on', None)
943936
spawn_timeout = int(get(section, 'spawn_timeout', 60))
944937

@@ -1067,7 +1060,6 @@ def get(section, opt, *args, **kwargs):
10671060
redirect_stderr=redirect_stderr,
10681061
environment=environment,
10691062
serverurl=serverurl,
1070-
runningregex=runningregex,
10711063
depends_on=depends_on,
10721064
spawn_timeout=spawn_timeout,
10731065
)
@@ -1889,7 +1881,7 @@ class ProcessConfig(Config):
18891881
'stopsignal', 'stopwaitsecs', 'stopasgroup', 'killasgroup',
18901882
'exitcodes', 'redirect_stderr' ]
18911883
optional_param_names = [ 'environment', 'serverurl',
1892-
'runningregex', 'depends_on', 'spawn_timeout' ]
1884+
'depends_on', 'spawn_timeout' ]
18931885

18941886
def __init__(self, options, **params):
18951887
self.options = options

supervisor/process.py

Lines changed: 74 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,6 @@
3333

3434
from supervisor.socket_manager import SocketManager
3535

36-
from supervisor.rpcinterface import SupervisorNamespaceRPCInterface
37-
from supervisor.xmlrpc import (
38-
capped_int,
39-
Faults,
40-
RPCError,
41-
)
42-
4336
@functools.total_ordering
4437
class Subprocess(object):
4538

@@ -200,96 +193,95 @@ def record_spawnerr(self, msg):
200193
self.config.options.logger.info("spawnerr: %s" % msg)
201194

202195
def queue_all_dependee_processes(self, supervisor):
203-
if self.config.name not in supervisor.process_spawn_set:
204-
supervisor.process_spawn_queue.append(self)
205-
supervisor.process_spawn_set.add(self.config.name)
206-
# all dependees that are not in queue and not in STARTING need to be added to queue.
196+
if (self.config.name not in supervisor.process_spawn_dict.keys() or
197+
self.config.name not in supervisor.process_started_dict.keys()):
198+
supervisor.process_spawn_dict[self.config.name] = self
207199
if self.config.depends_on is not None:
208200
for dependee in self.config.depends_on.values():
209-
if dependee.state is not ProcessStates.RUNNING:
210-
ready_to_be_spawned = False
211-
if dependee.state is not ProcessStates.STARTING:
212-
if dependee.config.name not in supervisor.process_spawn_set:
213-
supervisor.process_spawn_queue.append(dependee)
214-
supervisor.process_spawn_set.add(dependee.config.name)
201+
if dependee.state is not ProcessStates.RUNNING and dependee.state is not ProcessStates.STARTING:
202+
if (dependee.config.name not in supervisor.process_spawn_dict.keys() or
203+
dependee.config.name not in supervisor.process_started_dict.keys()):
204+
supervisor.process_spawn_dict[dependee.config.name] = dependee
215205
dependee.queue_all_dependee_processes(supervisor)
216206

217-
218207
def spawn(self, supervisor=None):
219208
"""Start the subprocess. It must not be running already.
220209
221210
Return the process id. If the fork() call fails, return None.
222211
"""
223-
# spawn if all dependees are running - else add to queue if not in queue already
224-
ready_to_be_spawned = True
225-
226-
options = self.config.options
227-
processname = as_string(self.config.name)
228-
229-
if self.pid:
230-
msg = 'process \'%s\' already running' % processname
231-
options.logger.warn(msg)
212+
if self.config.depends_on is not None:
213+
if any([dependee.state is not ProcessStates.RUNNING for dependee in
214+
self.config.depends_on.values()]):
215+
self.queue_all_dependee_processes(supervisor)
232216
return
233217

234-
self.killing = False
235-
self.spawnerr = None
236-
self.exitstatus = None
237-
self.system_stop = False
238-
self.administrative_stop = False
218+
options = self.config.options
219+
processname = as_string(self.config.name)
239220

240-
self.laststart = time.time()
221+
if self.pid:
222+
msg = 'process \'%s\' already running' % processname
223+
options.logger.warn(msg)
224+
return
241225

242-
self._assertInState(ProcessStates.EXITED, ProcessStates.FATAL,
243-
ProcessStates.BACKOFF, ProcessStates.STOPPED)
226+
self.killing = False
227+
self.spawnerr = None
228+
self.exitstatus = None
229+
self.system_stop = False
230+
self.administrative_stop = False
244231

245-
self.change_state(ProcessStates.STARTING)
232+
self.laststart = time.time()
246233

247-
try:
248-
filename, argv = self.get_execv_args()
249-
except ProcessException as what:
250-
self.record_spawnerr(what.args[0])
251-
self._assertInState(ProcessStates.STARTING)
252-
self.change_state(ProcessStates.BACKOFF)
253-
return
234+
self._assertInState(ProcessStates.EXITED, ProcessStates.FATAL,
235+
ProcessStates.BACKOFF, ProcessStates.STOPPED)
254236

255-
try:
256-
self.dispatchers, self.pipes = self.config.make_dispatchers(self)
257-
except (OSError, IOError) as why:
258-
code = why.args[0]
259-
if code == errno.EMFILE:
260-
# too many file descriptors open
261-
msg = 'too many open files to spawn \'%s\'' % processname
262-
else:
263-
msg = 'unknown error making dispatchers for \'%s\': %s' % (
264-
processname, errno.errorcode.get(code, code))
265-
self.record_spawnerr(msg)
266-
self._assertInState(ProcessStates.STARTING)
267-
self.change_state(ProcessStates.BACKOFF)
268-
return
237+
self.change_state(ProcessStates.STARTING)
269238

270-
try:
271-
pid = options.fork()
272-
except OSError as why:
273-
code = why.args[0]
274-
if code == errno.EAGAIN:
275-
# process table full
276-
msg = ('Too many processes in process table to spawn \'%s\'' %
277-
processname)
278-
else:
279-
msg = 'unknown error during fork for \'%s\': %s' % (
280-
processname, errno.errorcode.get(code, code))
281-
self.record_spawnerr(msg)
282-
self._assertInState(ProcessStates.STARTING)
283-
self.change_state(ProcessStates.BACKOFF)
284-
options.close_parent_pipes(self.pipes)
285-
options.close_child_pipes(self.pipes)
286-
return
239+
try:
240+
filename, argv = self.get_execv_args()
241+
except ProcessException as what:
242+
self.record_spawnerr(what.args[0])
243+
self._assertInState(ProcessStates.STARTING)
244+
self.change_state(ProcessStates.BACKOFF)
245+
return
287246

288-
if pid != 0:
289-
return self._spawn_as_parent(pid)
247+
try:
248+
self.dispatchers, self.pipes = self.config.make_dispatchers(self)
249+
except (OSError, IOError) as why:
250+
code = why.args[0]
251+
if code == errno.EMFILE:
252+
# too many file descriptors open
253+
msg = 'too many open files to spawn \'%s\'' % processname
254+
else:
255+
msg = 'unknown error making dispatchers for \'%s\': %s' % (
256+
processname, errno.errorcode.get(code, code))
257+
self.record_spawnerr(msg)
258+
self._assertInState(ProcessStates.STARTING)
259+
self.change_state(ProcessStates.BACKOFF)
260+
return
290261

262+
try:
263+
pid = options.fork()
264+
except OSError as why:
265+
code = why.args[0]
266+
if code == errno.EAGAIN:
267+
# process table full
268+
msg = ('Too many processes in process table to spawn \'%s\'' %
269+
processname)
291270
else:
292-
return self._spawn_as_child(filename, argv)
271+
msg = 'unknown error during fork for \'%s\': %s' % (
272+
processname, errno.errorcode.get(code, code))
273+
self.record_spawnerr(msg)
274+
self._assertInState(ProcessStates.STARTING)
275+
self.change_state(ProcessStates.BACKOFF)
276+
options.close_parent_pipes(self.pipes)
277+
options.close_child_pipes(self.pipes)
278+
return
279+
280+
if pid != 0:
281+
return self._spawn_as_parent(pid)
282+
283+
else:
284+
return self._spawn_as_child(filename, argv)
293285

294286
def _spawn_as_parent(self, pid):
295287
# Parent
@@ -677,7 +669,7 @@ def __repr__(self):
677669
def get_state(self):
678670
return self.state
679671

680-
def transition(self, supervisord_instance=None):
672+
def transition(self, supervisor=None):
681673
now = time.time()
682674
state = self.state
683675

@@ -698,15 +690,7 @@ def transition(self, supervisord_instance=None):
698690
self.spawn(supervisor)
699691
elif state == ProcessStates.STOPPED and not self.laststart:
700692
if self.config.autostart:
701-
# STOPPED -> STARTING
702-
# make sure dependent processes are spawned before
703-
# check if the process is dependent upon any other process and if so,
704-
# make sure that one is in the RUNNING state
705-
if self.config.depends_on is not None:
706-
rpc_interface = SupervisorNamespaceRPCInterface(supervisord_instance)
707-
rpc_interface.startProcess(self.group.config.name + ':' + self.config.name)
708-
else:
709-
self.spawn()
693+
self.spawn(supervisor)
710694
elif state == ProcessStates.BACKOFF:
711695
if self.backoff <= self.config.startretries:
712696
if now > self.delay:
@@ -715,7 +699,7 @@ def transition(self, supervisord_instance=None):
715699

716700
processname = as_string(self.config.name)
717701
if state == ProcessStates.STARTING:
718-
if now - self.laststart > self.config.startsecs and not self.config.runningregex:
702+
if now - self.laststart > self.config.startsecs:
719703
# STARTING -> RUNNING if the proc has started
720704
# successfully and it has stayed up for at least
721705
# proc.config.startsecs,
@@ -728,27 +712,6 @@ def transition(self, supervisord_instance=None):
728712
'> than %s seconds (startsecs)' % self.config.startsecs)
729713
logger.info('success: %s %s' % (processname, msg))
730714

731-
if self.config.runningregex:
732-
logfile = getattr(self.config, 'stdout_logfile')
733-
logfile_as_str = as_string(readFile(logfile, self.log_offset, 0))
734-
735-
# delete ascii escape sequence and newlines with regular expression
736-
ansi_escape = re.compile(r'(\x9B|\x1B\[)[0-?]*[ -\/]*[@-~]|\n')
737-
logfile_as_str = ansi_escape.sub('', logfile_as_str)
738-
739-
# STARTING -> RUNNING if the process has started
740-
# successfully and the runningregex is met
741-
if self.config.runningregex.match(logfile_as_str):
742-
self.delay = 0
743-
self.backoff = 0
744-
self._assertInState(ProcessStates.STARTING)
745-
self.change_state(ProcessStates.RUNNING)
746-
msg = ('entered RUNNING state, found runningregex in stdout')
747-
logger.info('success: %s %s' % (processname, msg))
748-
749-
750-
751-
752715
if state == ProcessStates.BACKOFF:
753716
if self.backoff > self.config.startretries:
754717
# BACKOFF -> FATAL if the proc has exceeded its number
@@ -894,9 +857,9 @@ def before_remove(self):
894857
pass
895858

896859
class ProcessGroup(ProcessGroupBase):
897-
def transition(self, supervisord_instance):
860+
def transition(self, supervisor):
898861
for proc in self.processes.values():
899-
proc.transition(supervisord_instance)
862+
proc.transition(supervisor)
900863

901864
class FastCGIProcessGroup(ProcessGroup):
902865

0 commit comments

Comments
 (0)