Python Processes는 다시 시작한 후 Sigterm / Sigint에 대한 응답을 중지합니다.
문제
Watchdog 프로세스를 사용하여 실행하는 일부 파이썬 프로세스에 이상한 문제가 있습니다.
Watchdog 프로세스는 Python으로 작성되었으며 부모이며 기능이 있습니다. start_child (이름) 사용하는 하위 프로세스 .popen 아동 과정을 열기 위해. Popen 객체는 워치 독이 사용 프로세스를 모니터링 할 수 있도록 기록됩니다. 투표() 결국에는 끝납니다 끝내다() 필요할 때. 아이가 예기치 않게 죽으면 워치 독이 전화를 겁니다 start_child (이름) 다시 새로운 Popen 객체를 녹음합니다.
7 개의 아동 프로세스가 있으며,이 과정은 모두 파이썬입니다. 어린이 중 하나를 수동으로 운영하면 Sigterm 또는 Sigint를 사용하여 보낼 수 있습니다. 죽이다 그리고 내가 기대하는 결과를 얻습니다 (프로세스 끝).
그러나 워치 독 과정에서 달리면 아이는 첫 번째 신호. Watchdog이 아이를 다시 시작하면 새로운 아동 과정이 더 이상 Sigterm 또는 Sigint에 응답하지 않습니다. 나는 이것을 원인하는 것이 무엇인지 전혀 모른다.
Watchdog.py
class watchdog:
# <snip> various init stuff
def start(self):
self.running = true
kids = ['app1', 'app2', 'app3', 'app4', 'app5', 'app6', 'app7']
self.processes = {}
for kid in kids:
self.start_child(kid)
self.thread = threading.Thread(target=self._monitor)
self.thread.start()
while self.running:
time.sleep(10)
def start_child(self, name):
try:
proc = subprocess.Popen(name)
self.processes[name] = proc
except:
print "oh no"
else:
print "started child ok"
def _monitor(self):
while self.running:
time.sleep(1)
if self.running:
for kid, proc in self.processes.iteritems():
if proc.poll() is not None: # process ended
self.start_child(kid)
그래서 무슨 일이 일어나는지 Watchdog.start () 7 개의 프로세스를 모두 시작하고 프로세스 sigterm을 보내면 종료되고 모니터 스레드가 다시 시작됩니다. 그러나 새로운 프로세스를 보내면 Sigterm을 보내면 무시합니다.
다시 시작된 프로세스에 -15를 계속해서 킬을 보낼 수 있어야합니다. 다시 시작한 후 무시하는 이유는 무엇입니까?
해결책
여기에 설명 된대로 : http://blogs.gentoo.org/agaffney/2005/03/18/python_sucks , Python이 새 스레드를 생성하면 해당 스레드 (및 스레드가 생성되는 모든 프로세스의 경우)에 대한 모든 신호를 차단합니다.
CTYPES를 통해 불리는 SIGPROCMASK를 사용하여 이것을 수정했습니다. 이것은 "올바른"방법 일 수도 있고 아닐 수도 있지만 작동합니다.
어린이 과정에서 __init__
:
libc = ctypes.cdll.LoadLibrary("libc.so")
mask = '\x00' * 17 # 16 byte empty mask + null terminator
libc.sigprocmask(3, mask, None) # '3' on FreeBSD is the value for SIG_SETMASK
다른 팁
CTypes가 아닌 Python 내에서 기본 신호 핸들러를 복원하는 것이 더 낫지 않습니까? 자녀 프로세스에서 신호 모듈을 사용하십시오.
import signal
for sig in range(1, signal.NSIG):
try:
signal.signal(sig, signal.SIG_DFL)
except RuntimeError:
pass
RuntimeError는 잡을 수없는 Sigkill과 같은 신호를 설정하려고 할 때 발생합니다.