浏览代码

Trace: Must also find pickleable type

Ask Solem 12 年之前
父节点
当前提交
80bd5ac47a
共有 2 个文件被更改,包括 31 次插入13 次删除
  1. 7 2
      celery/task/trace.py
  2. 24 11
      celery/utils/serialization.py

+ 7 - 2
celery/task/trace.py

@@ -30,7 +30,10 @@ from celery.app import set_default_app
 from celery.app.task import Task as BaseTask, Context
 from celery.app.task import Task as BaseTask, Context
 from celery.datastructures import ExceptionInfo
 from celery.datastructures import ExceptionInfo
 from celery.exceptions import Ignore, RetryTaskError
 from celery.exceptions import Ignore, RetryTaskError
-from celery.utils.serialization import get_pickleable_exception
+from celery.utils.serialization import (
+    get_pickleable_exception,
+    get_pickleable_etype,
+)
 from celery.utils.log import get_logger
 from celery.utils.log import get_logger
 
 
 _logger = get_logger(__name__)
 _logger = get_logger(__name__)
@@ -128,7 +131,9 @@ class TraceInfo(object):
         type_, _, tb = sys.exc_info()
         type_, _, tb = sys.exc_info()
         try:
         try:
             exc = self.retval
             exc = self.retval
-            einfo = ExceptionInfo((type_, get_pickleable_exception(exc), tb))
+            einfo = ExceptionInfo()
+            einfo.exception = get_pickleable_exception(einfo.exception)
+            einfo.type = get_pickleable_etype(einfo.type)
             if store_errors:
             if store_errors:
                 task.backend.mark_as_failure(req.id, exc, einfo.traceback)
                 task.backend.mark_as_failure(req.id, exc, einfo.traceback)
             task.on_failure(exc, req.id, req.args, req.kwargs, einfo)
             task.on_failure(exc, req.id, req.args, req.kwargs, einfo)

+ 24 - 11
celery/utils/serialization.py

@@ -50,7 +50,8 @@ else:
         return type(name, (parent,), {'__module__': module})
         return type(name, (parent,), {'__module__': module})
 
 
 
 
-def find_nearest_pickleable_exception(exc):
+def find_pickleable_exception(exc, loads=pickle.loads,
+                              dumps=pickle.dumps):
     """With an exception instance, iterate over its super classes (by mro)
     """With an exception instance, iterate over its super classes (by mro)
     and find the first super exception that is pickleable.  It does
     and find the first super exception that is pickleable.  It does
     not go below :exc:`Exception` (i.e. it skips :exc:`Exception`,
     not go below :exc:`Exception` (i.e. it skips :exc:`Exception`,
@@ -65,7 +66,19 @@ def find_nearest_pickleable_exception(exc):
     :rtype :exc:`Exception`:
     :rtype :exc:`Exception`:
 
 
     """
     """
-    cls = exc.__class__
+    exc_args = getattr(exc, 'args', [])
+    for supercls in itermro(exc.__class__, unwanted_base_classes):
+        try:
+            superexc = supercls(*exc_args)
+            loads(dumps(superexc))
+        except:
+            pass
+        else:
+            return superexc
+find_nearest_pickleable_exception = find_pickleable_exception  # XXX compat
+
+
+def itermro(cls, stop):
     getmro_ = getattr(cls, 'mro', None)
     getmro_ = getattr(cls, 'mro', None)
 
 
     # old-style classes doesn't have mro()
     # old-style classes doesn't have mro()
@@ -77,18 +90,11 @@ def find_nearest_pickleable_exception(exc):
         getmro_ = lambda: inspect.getmro(cls)
         getmro_ = lambda: inspect.getmro(cls)
 
 
     for supercls in getmro_():
     for supercls in getmro_():
-        if supercls in unwanted_base_classes:
+        if supercls in stop:
             # only BaseException and object, from here on down,
             # only BaseException and object, from here on down,
             # we don't care about these.
             # we don't care about these.
             return
             return
-        try:
-            exc_args = getattr(exc, 'args', [])
-            superexc = supercls(*exc_args)
-            pickle.loads(pickle.dumps(superexc))
-        except:
-            pass
-        else:
-            return superexc
+        yield
 
 
 
 
 def create_exception_cls(name, module, parent=None):
 def create_exception_cls(name, module, parent=None):
@@ -171,6 +177,13 @@ def get_pickleable_exception(exc):
     return UnpickleableExceptionWrapper.from_exception(exc)
     return UnpickleableExceptionWrapper.from_exception(exc)
 
 
 
 
+def get_pickleable_etype(cls, loads=pickle.loads, dumps=pickle.dumps):
+    try:
+        loads(dumps(cls))
+    except:
+        return Exception
+
+
 def get_pickled_exception(exc):
 def get_pickled_exception(exc):
     """Get original exception from exception pickled using
     """Get original exception from exception pickled using
     :meth:`get_pickleable_exception`."""
     :meth:`get_pickleable_exception`."""