X-Git-Url: https://git.llucax.com/software/pymin.git/blobdiff_plain/5a99100c41547b2ca2669ddc2ae7f54069e9e7e3..2e8aebbf35feff4c6e68c850193895c57acdd92f:/pymin/procman.py?ds=sidebyside diff --git a/pymin/procman.py b/pymin/procman.py index eb11a27..0d67b9b 100644 --- a/pymin/procman.py +++ b/pymin/procman.py @@ -24,20 +24,21 @@ class ProcessInfo: self.clear() def clear(self): self._dont_run = False - self.signal = None - self.process = None - self.error_count = 0 + self._signal = None + self._process = None + self._error_count = 0 def start(self): assert self.process is None self.restart() def restart(self): self.clear() log.debug(u'ProcessInfo.restart(): executing %s', self.command) - self.process = subprocess.Popen(self.command, *self.args, **self.kwargs) + self._process = subprocess.Popen(self.command, + *self.args, **self.kwargs) def stop(self): assert self.process is not None self._dont_run = True - if self.signal == signal.SIGTERM or self.signal == signal.SIGKILL: + if self._signal == signal.SIGTERM or self._signal == signal.SIGKILL: # Allready stopped, kill it self.kill(signal.SIGKILL) else: @@ -48,13 +49,19 @@ class ProcessInfo: self.process.pid, signum) assert self.process is not None os.kill(self.process.pid, signum) - self.signal = signum + self._signal = signum @property def running(self): return self.process is not None and self.process.poll() is None @property def name(self): return self._name + @property + def process(self): + return self._process + @property + def error_count(self): + return self._error_count def __repr__(self): pid = None if self.process is not None: @@ -76,12 +83,16 @@ class ProcessManager: log.debug(u'ProcessManager.register(%s, %s, %s, %s, %s, %s, %s)', name, command, callback, persist, max_errors, args, kwargs) assert not self.has(name) - self.services[name] = ProcessInfo(name, command, callback, persist, - max_errors, args, kwargs) + pi = ProcessInfo(name, command, callback, persist, max_errors, + args, kwargs) + self.services[name] = pi + return pi def unregister(self, name): log.debug(u'ProcessManager.unregister(%s)', name) + pi = self.services[name] del self.services[name] + return pi def _call(self, pi): pi.start() @@ -95,6 +106,7 @@ class ProcessManager: pi = ProcessInfo(name, command, callback, persist, max_errors, args, kwargs) self._call(pi) + return pi def start(self, name): log.debug(u'ProcessManager.start(%s)', name) @@ -112,11 +124,15 @@ class ProcessManager: # process (added with once()) if name in self.namemap: pi = self.namemap[name] + # the process will change its PID, so we delete it while we know it + del self.pidmap[pi.process.pid] pi.stop() pi.process.wait() pi.restart() + # add the new PID + self.pidmap[pi.process.pid] = pi else: - self.services[name].start() + self.start(name) def kill(self, name, signum): log.debug(u'ProcessManager.kill(%s, %s)', name, signum) @@ -143,24 +159,25 @@ class ProcessManager: log.debug(u'ProcessManager.sigchild_handler: ' u'calling %s(%s)', p.callback.__name__, p) p.callback(self, p) - if p._dont_run or not p.persist or p.error_count >= p.max_errors: + if (p._dont_run or not p.persist + or p._error_count >= p.max_errors): log.debug(u"ProcessManager.sigchild_handler: can't " u'persist, dont_run=%s, persist=%s, error_cout=%s, ' u'max_errors=%s', p._dont_run, p.persist, - p.error_count, p.max_errors) + p._error_count, p.max_errors) del self.namemap[p.name] del self.pidmap[pid] p.clear() else: log.debug(u'ProcessManager.sigchild_handler: persist') if p.process.returncode == 0: - p.error_count = 0 + p._error_count = 0 log.debug(u'ProcessManager.sigchild_handler: ' u'return OK, resetting error_count') else: - p.error_count += 1 + p._error_count += 1 log.debug(u'ProcessManager.sigchild_handler: return' - u'not 0, error_count + 1 = %s', p.error_count) + u'not 0, error_count + 1 = %s', p._error_count) del self.pidmap[pid] p.restart() self.pidmap[p.process.pid] = p @@ -181,6 +198,8 @@ class ProcessManager: if name in self.pidmap: return self.pidmap[name] raise KeyError, name + # Syntax sugar for self[name] + __getitem__ = get def has(self, name): if isinstance(name, basestring): # is a name @@ -192,12 +211,8 @@ class ProcessManager: if name in self.pidmap: return True return False - - def __getitem__(self, name): - return self.get(name) - - def __contains__(self, name): - return self.has(name) + # Syntax sugar for name in self + __contains__ = has if __name__ == '__main__': @@ -253,6 +268,9 @@ if __name__ == '__main__': assert 'test-service' in manager.services assert 'test-service' not in manager.namemap assert not get('test-service').running + assert manager['test-service'] == get('test-service') + assert has('test-service') + assert 'test-service' in manager register('test-service-2', ('sleep', '3'), notify, False) assert 'test-service-2' in manager.services @@ -265,10 +283,20 @@ if __name__ == '__main__': assert 'test-once' not in manager.services assert 'test-once' in manager.namemap assert get('test-once').running + assert get('test-once').process.pid + pid = get('test-once').process.pid + restart('test-once') + assert pid != get('test-once').process.pid + assert pid != manager.pidmap[get('test-once').process.pid].process.pid start('test-service') assert 'test-service' in manager.namemap assert get('test-service').running + assert get('test-service').process.pid + pid = get('test-service').process.pid + restart('test-service') + assert pid != get('test-service').process.pid + assert pid != manager.pidmap[get('test-service').process.pid].process.pid print "Known processes:", manager.services.keys() print "Waiting...", manager.namemap.keys() @@ -286,8 +314,12 @@ if __name__ == '__main__': assert 'test-once' not in manager.services assert 'test-once' not in manager.namemap + restart('test-service') + assert get('test-service').process.pid + assert manager.pidmap[get('test-service').process.pid].process.pid + once('test-wait', ('sleep', '2')) - print 'test-wait returned?', get('test-wait').process.poll() + print 'test-wait running?', get('test-wait').running assert get('test-wait').running print 'Waiting test-wait to return...' ret = get('test-wait').process.wait()