تتوقف عمليات Python عن الاستجابة لـ SIGTERM / SIGINT بعد إعادة تشغيلها

StackOverflow https://stackoverflow.com/questions/1133693

  •  16-09-2019
  •  | 
  •  

سؤال

أواجه مشكلة غريبة في تشغيل بعض عمليات بايثون باستخدام عملية المراقبة.

عملية المراقبة مكتوبة بلغة بايثون وهي الأصل ولها وظيفة تسمى start_child(الاسم) الذي يستخدم عملية فرعية.فتح لفتح عملية الطفل.يتم تسجيل كائن Popen حتى تتمكن هيئة المراقبة من مراقبة العملية باستخدامه تصويت() وإنهاء الأمر في النهاية إنهاء () عند الاحتياج.إذا مات الطفل بشكل غير متوقع، تتصل الوكالة الرقابية start_child(الاسم) مرة أخرى ويسجل كائن Popen الجديد.

هناك 7 عمليات فرعية، جميعها أيضًا بيثون.إذا قمت بتشغيل أي من الأطفال يدويًا، فيمكنني إرسال SIGTERM أو SIGINT باستخدام قتل والحصول على النتائج التي أتوقعها (تنتهي العملية).

ومع ذلك، عند الهروب من عملية المراقبة، لن ينتهي الطفل إلا بعد أولاً الإشارة.عندما تقوم جهة المراقبة بإعادة تشغيل الطفل، لم تعد العملية الفرعية الجديدة تستجيب لـ SIGTERM أو SIGINT.ليس لدي أي فكرة عما يسبب هذا.

الوكالة الدولية للطاقة.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)

إذن ما يحدث هو الوكالة الدولية للطاقة.بدء() يطلق جميع العمليات السبع، وإذا أرسلت أي عملية SIGTERM، فإنها تنتهي، ويبدأ خيط المراقبة تشغيلها مرة أخرى.ومع ذلك، إذا قمت بعد ذلك بإرسال العملية الجديدة SIGTERM، فإنها تتجاهلها.

يجب أن أكون قادرًا على الاستمرار في إرسال kill -15 إلى العمليات المعاد تشغيلها مرارًا وتكرارًا.لماذا يتجاهلونها بعد إعادة التشغيل؟

هل كانت مفيدة؟

المحلول

كما هو موضح هنا : http://blogs.gentoo.org/agaffney/2005/03/18/python_sucks ، عندما تنشئ بايثون سلسلة رسائل جديدة، فإنها تحظر جميع الإشارات الخاصة بهذا السلسلة (ولأي عمليات تنتج سلسلة المحادثات).

لقد أصلحت هذه المشكلة باستخدام sigprocmask، الذي تم استدعاؤه من خلال ctypes.قد تكون هذه هي أو لا تكون الطريقة "الصحيحة" للقيام بذلك، ولكنها ناجحة.

في عملية الطفل، أثناء __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؟في عملية طفلك، استخدم وحدة الإشارة:

import signal
for sig in range(1, signal.NSIG):
    try:
        signal.signal(sig, signal.SIG_DFL)
    except RuntimeError:
        pass

يظهر خطأ RuntimeError عند محاولة تعيين إشارات مثل SIGKILL والتي لا يمكن التقاطها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top