Repository: celery/celery

Issue:
Json task result serializer + Exception = Fail
When a task raises an exception, celeryd gets an exception in kombu:

```
[2011-06-28 18:34:31,540: ERROR/MainProcess] Task tasks.error[5c493298-b7e9-4535-a697-e271298b8b18] raised exception: TypeError('Exception() is not JSON serializable',)
Traceback (most recent call last):
  File "<virtualenv>/lib/python2.7/site-packages/celery/worker/job.py", line 109, in execute_safe
    return self.execute(*args, **kwargs)
  File "<virtualenv>/lib/python2.7/site-packages/celery/worker/job.py", line 127, in execute
    return super(WorkerTaskTrace, self).execute()
  File "<virtualenv>/lib/python2.7/site-packages/celery/execute/trace.py", line 76, in execute
    retval = self._trace()
  File "<virtualenv>/lib/python2.7/site-packages/celery/execute/trace.py", line 90, in _trace
    r = handler(trace.retval, trace.exc_type, trace.tb, trace.strtb)
  File "<virtualenv>/lib/python2.7/site-packages/celery/worker/job.py", line 155, in handle_failure
    exc = self.task.backend.mark_as_failure(self.task_id, exc, strtb)
  File "<virtualenv>/lib/python2.7/site-packages/celery/backends/base.py", line 45, in mark_as_failure
    traceback=traceback)
  File "<virtualenv>/lib/python2.7/site-packages/celery/backends/base.py", line 157, in store_result
    return self._store_result(task_id, result, status, traceback, **kwargs)
  File "<virtualenv>/lib/python2.7/site-packages/celery/backends/amqp.py", line 128, in _store_result
    "traceback": traceback})
  File "<virtualenv>/lib/python2.7/site-packages/kombu/connection.py", line 230, in _insured
    return fun(*args, **kwargs)
  File "<virtualenv>/lib/python2.7/site-packages/celery/backends/amqp.py", line 101, in _publish_result
    self._create_producer(task_id, channel).publish(meta)
  File "<virtualenv>/lib/python2.7/site-packages/kombu/messaging.py", line 124, in publish
    compression, headers)
  File "<virtualenv>/lib/python2.7/site-packages/kombu/messaging.py", line 147, in _prepare
    body) = encode(body, serializer=serializer)
  File "<virtualenv>/lib/python2.7/site-packages/kombu/serialization.py", line 119, in encode
    payload = encoder(data)
  File "<virtualenv>/lib/python2.7/site-packages/anyjson/__init__.py", line 129, in <lambda>
    serialize = lambda value: implementation.serialize(value)
  File "<virtualenv>/lib/python2.7/site-packages/anyjson/__init__.py", line 91, in serialize
    raise TypeError(*exc.args)
TypeError: Exception() is not JSON serializable
```



Discussion:

Resolving patch:
diff --git a/celery/backends/base.py b/celery/backends/base.py
--- a/celery/backends/base.py
+++ b/celery/backends/base.py
@@ -1,5 +1,6 @@
 """celery.backends.base"""
 import time
+import sys
 
 from datetime import timedelta
 
@@ -8,8 +9,9 @@
 from celery.utils import timeutils
 from celery.utils.serialization import pickle, get_pickled_exception
 from celery.utils.serialization import get_pickleable_exception
+from celery.utils.serialization import create_exception_cls
 from celery.datastructures import LocalCache
-
+from celery.app import app_or_default
 
 class BaseBackend(object):
     """Base backend class."""
@@ -33,7 +35,7 @@ def prepare_expires(self, value, type=None):
         return value
 
     def encode_result(self, result, status):
-        if status in self.EXCEPTION_STATES:
+        if status in self.EXCEPTION_STATES and isinstance(result, Exception):
             return self.prepare_exception(result)
         else:
             return self.prepare_value(result)
@@ -68,11 +70,18 @@ def mark_as_revoked(self, task_id):
 
     def prepare_exception(self, exc):
         """Prepare exception for serialization."""
-        return get_pickleable_exception(exc)
+        if (app_or_default().conf["CELERY_RESULT_SERIALIZER"] in ("pickle", "yaml")):
+            return get_pickleable_exception(exc)
+        return {
+            "exc_type": type(exc).__name__,
+            "exc_message": str(exc),
+        }
 
     def exception_to_python(self, exc):
         """Convert serialized exception to Python exception."""
-        return get_pickled_exception(exc)
+        if (app_or_default().conf["CELERY_RESULT_SERIALIZER"] in ("pickle", "yaml")):
+            return get_pickled_exception(exc)
+        return create_exception_cls(exc["exc_type"].encode("utf-8"), sys.modules[__name__])
 
     def prepare_value(self, result):
         """Prepare value for storage."""


Test patch: