2012-02-09 12 views
13

मैं भूगर्भ का उपयोग कर एक आवेदन बना रहा हूं। मेरा ऐप अब बड़ा हो रहा है क्योंकि बहुत सी नौकरियां पैदा हो रही हैं और नष्ट हो गई हैं। अब मैंने देखा है कि जब इनमें से एक नौकरियां मेरे पूरे एप्लिकेशन को दुर्घटनाग्रस्त कर देती हैं तो बस चलती रहती है (यदि अपवाद एक गैर मुख्य ग्रीनलेट से आया है) जो ठीक है। लेकिन समस्या यह है कि मुझे त्रुटि देखने के लिए अपने कंसोल को देखना होगा। तो मेरे आवेदन का कुछ हिस्सा "मर" सकता है और मुझे इसके बारे में तुरंत पता नहीं है और ऐप चल रहा है।नौकरियों में गीता अपवादों की निगरानी

कोशिश करने के सामान के साथ अपने ऐप को झटकेदार एक साफ समाधान प्रतीत नहीं होता है। शायद एक कस्टम स्पॉन फ़ंक्शन जो कुछ त्रुटि रिपोर्टिंग करता है?

भूगर्भ नौकरियों/ग्रीनलेट्स की निगरानी करने का उचित तरीका क्या है? अपवाद पकड़ो?

मेरे मामले में मैं कुछ अलग स्रोतों की घटनाओं को सुनता हूं और मुझे प्रत्येक अलग से निपटना चाहिए। 5 नौकरियां बेहद महत्वपूर्ण हैं। वेबसर्वर ग्रीनलेट, वेबसाकेट ग्रीनलेट, डेटाबेस ग्रीनलेट, अलार्म ग्रीनलेट, और जेएमक्यू ग्रीनलेट। यदि उनमें से कोई भी 'मर जाता है' तो मेरा आवेदन पूरी तरह से मरना चाहिए। मरने वाली अन्य नौकरियां महत्वपूर्ण नहीं हैं। उदाहरण के लिए, यह संभव है कि वेबस्केट ग्रीनलेट कुछ अपवाद के कारण मर जाता है और बाकी के अनुप्रयोग ठीक चलते रहते हैं जैसे कुछ नहीं हुआ। यह अब पूरी तरह से बेकार और खतरनाक है और इसे कड़ी मेहनत करनी चाहिए।

+0

मैंने मिशन को महत्वपूर्ण ग्रीनलेट बहुत छोटे बना दिया है। (कोड की 8 पंक्तियां) और वे अपनी बारी पर ग्रीनलेट्स को जन्म देते हैं जिसके लिए यह दुर्घटनाग्रस्त हो जाता है। – Stephan

उत्तर

12

मुझे लगता है कि सबसे अच्छा तरीका अपवाद को पकड़ने के लिए होगा और आप sys.exit() करते हैं (आपको SystemExit प्रक्रिया से बाहर नहीं निकलने के बाद से आपको Gevent 1.0 की आवश्यकता होगी)।

लिंक_एक्सप्शन का उपयोग करने का एक और तरीका है, जिसे कहा जाएगा कि ग्रीनलेट अपवाद के साथ मर गया है या नहीं।

spawn(important_greenlet).link_exception(lambda *args: sys.exit("important_greenlet died")) 

नोट, आपको इसके लिए काम करने के लिए gevent 1.0 की भी आवश्यकता है।

पर 0.13.6 हैं, तो प्रक्रिया को मारने के लिए कुछ इस तरह करते हैं:

gevent.get_hub().parent.throw(SystemExit()) 
+0

आपका नया भविष्य कार्यालय बीटीडब्ल्यू अच्छा दिख रहा है;) – Stephan

+0

0.13.6 पर मेरे पास 'gevent.get_hub()' नहीं है। मेरे पास 'gevent.getcurrent()' है, लेकिन मूल विशेषता 'कोई नहीं' थी। – scottm

+0

@scottm gevent.hub.get_hub() तब कोशिश करें। –

3

आप चौकीदार कार्य करने के लिए एक करने के लिए अपने greenlets के सभी greenlet.link_exception() करना चाहते हैं।

जेनिटर फ़ंक्शन किसी भी ग्रीनलेट को पारित किया जाएगा जो मर जाता है, जिससे यह देखने के लिए greenlet.exception का निरीक्षण कर सकता है, और यदि आवश्यक हो तो इसके बारे में कुछ करें।

+0

पूरी प्रक्रिया को मारने की तुलना में अधिक समझदार तरीका। –

0

greenlet.link_exception() के साथ मुख्य समस्या यह है कि यह ट्रेसबैक पर कोई जानकारी नहीं देता है जो लॉग इन करने के लिए वास्तव में महत्वपूर्ण हो सकता है। नौकरियों (जो मैंने नहीं किया प्रबंधन करने के लिए

from functools import wraps  

import gevent 

def async(wrapped): 

    def log_exc(func): 

     @wraps(wrapped) 
     def wrapper(*args, **kwargs): 
      try: 
       func(*args, **kwargs) 
      except Exception: 
       log.exception('%s', func) 
     return wrapper 

    @wraps(wrapped) 
    def wrapper(*args, **kwargs): 
     greenlet = gevent.spawn(log_exc(wrapped), *args, **kwargs) 

    return wrapper 
बेशक

, आप link_exception कॉल जोड़ सकते हैं:

ट्रैस बैक के साथ प्रवेश करने के लिए, मैं एक डेकोरेटर का उपयोग नौकरियों जो एक साधारण प्रवेश समारोह में अप्रत्यक्ष नौकरी कॉल spwan को आवश्यकता)

2

@ डेनिस और @ एलवो ने कहा, link_exception ठीक है, लेकिन मुझे लगता है कि इसके लिए एक बेहतर तरीका होगा, बिना आपके वर्तमान कोड को ग्रीनलेट को बदलने के लिए।

आम तौर पर, जब भी एक ग्रीनलेट में एक अपवाद फेंक दिया जाता है, _report_error विधि (gevent.greenlet.Greenlet में) उस ग्रीनलेट के लिए बुलाया जाएगा। यह कुछ लिंक करेगा जैसे सभी लिंक फ़ंक्शंस कॉल करें और आखिरकार, वर्तमान स्टैक से exc_info के साथ self.parent.handle_error पर कॉल करें।self.parent यहां वैश्विक Hub ऑब्जेक्ट है, इसका मतलब है, प्रत्येक ग्रीनलेट में किए गए सभी अपवाद हमेशा संभालने के लिए एक विधि के लिए केंद्रीकृत होंगे। डिफ़ॉल्ट रूप से Hub.handle_error अपवाद प्रकार को अलग करें, किसी प्रकार को अनदेखा करें और दूसरों को मुद्रित करें (जो हम हमेशा कंसोल में देखते हैं)।

Hub.handle_error विधि पैच करके, हम आसानी से अपने स्वयं के त्रुटि हैंडलर पंजीकृत कर सकते हैं और अब कभी भी कोई त्रुटि नहीं खो सकते हैं। मैं बनाने के लिए एक सहायक समारोह लिखा था यह हो:

from gevent.hub import Hub 


IGNORE_ERROR = Hub.SYSTEM_ERROR + Hub.NOT_ERROR 


def register_error_handler(error_handler): 

    Hub._origin_handle_error = Hub.handle_error 

    def custom_handle_error(self, context, type, value, tb): 
     if not issubclass(type, IGNORE_ERROR): 
      # print 'Got error from greenlet:', context, type, value, tb 
      error_handler(context, (type, value, tb)) 

     self._origin_handle_error(context, type, value, tb) 

    Hub.handle_error = custom_handle_error 

इसके इस्तेमाल के लिये पहले घटना पाश आरंभ नहीं हो जाता बस इसे कहते हैं:

def gevent_error_handler(context, exc_info): 
    """Here goes your custom error handling logics""" 
    e = exc_info[1] 
    if isinstance(e, SomeError): 
     # do some notify things 
     pass 
    sentry_client.captureException(exc_info=exc_info) 

register_error_handler(gevent_error_handler) 

यह समाधान gevent 1.0.2 और 1.1 के तहत परीक्षण किया गया है बी 3, हम इसे सेंड्री (एक अपवाद ट्रैकिंग सिस्टम) को ग्रीनलेट त्रुटि जानकारी भेजने के लिए उपयोग करते हैं, यह अब तक बहुत अच्छी तरह से काम करता है।

संबंधित मुद्दे