Repository: celery/celery
File: celery/backends/base.py (Python)

Code before:
            backend = app._tasks[callback.task].backend
        except KeyError:
            backend = self
        try:
            group(
                [app.signature(errback)
                 for errback in callback.options.get('link_error') or []],
                app=app,
            ).apply_async((callback.id,))
        except Exception as eb_exc:  # pylint: disable=broad-except
            return backend.fail_from_current_stack(callback.id, exc=eb_exc)
        else:
            return backend.fail_from_current_stack(callback.id, exc=exc)

    def fail_from_current_stack(self, task_id, exc=None):
        type_, real_exc, tb = sys.exc_info()
        try:
            exc = real_exc if exc is None else exc
            exception_info = ExceptionInfo((type_, exc, tb))
            self.mark_as_failure(task_id, exc, exception_info.traceback)
            return exception_info
        finally:
            del tb

    def prepare_exception(self, exc, serializer=None):
        """Prepare exception for serialization."""
        serializer = self.serializer if serializer is None else serializer
        if serializer in EXCEPTION_ABLE_CODECS:
            return get_pickleable_exception(exc)
        exctype = type(exc)
        return {'exc_type': getattr(exctype, '__qualname__', exctype.__name__),
                'exc_message': ensure_serializable(exc.args, self.encode),
                'exc_module': exctype.__module__}

    def exception_to_python(self, exc):
        """Convert serialized exception to Python exception."""
        if exc:
            if not isinstance(exc, BaseException):
                exc_module = exc.get('exc_module')
                if exc_module is None:
                    cls = create_exception_cls(
                        from_utf8(exc['exc_type']), __name__)
                else:
                    exc_module = from_utf8(exc_module)
                    exc_type = from_utf8(exc['exc_type'])
                    try:
                        # Load module and find exception class in that
                        cls = sys.modules[exc_module]
                        # The type can contain qualified name with parent classes
                        for name in exc_type.split('.'):
                            cls = getattr(cls, name)

Review comment (performance):
Sorry I'm a little "late to the party" here, but if I may, I want to forward a couple of question for @heedong-jung (perhaps for a future improvement):

1. Could we use [`traceback.clear_frames()`][1], introduced in python 3.4, to avoid manually iterating over and clearing the frame data above?

2. Are we not able to add an integration test, to more explicitly check for memory leaks over task execution?

3. Would it be possible to reuse the code in `traceback_clear`, eeither by allowing passing a traceback object, or perhaps by splitting into separate "extract traceback from exception" and "clear traceback frames"?

4. Do you believe it's related to (or resolves) issue #6058 ?

I believe that with the above information, I can start working on improvements where needed.

[1]: https://docs.python.org/3.5/library/traceback.html#traceback.clear_frames

Code after:
            backend = app._tasks[callback.task].backend
        except KeyError:
            backend = self
        try:
            group(
                [app.signature(errback)
                 for errback in callback.options.get('link_error') or []],
                app=app,
            ).apply_async((callback.id,))
        except Exception as eb_exc:  # pylint: disable=broad-except
            return backend.fail_from_current_stack(callback.id, exc=eb_exc)
        else:
            return backend.fail_from_current_stack(callback.id, exc=exc)

    def fail_from_current_stack(self, task_id, exc=None):
        type_, real_exc, tb = sys.exc_info()
        try:
            exc = real_exc if exc is None else exc
            exception_info = ExceptionInfo((type_, exc, tb))
            self.mark_as_failure(task_id, exc, exception_info.traceback)
            return exception_info
        finally:
            if sys.version_info >= (3, 5, 0):
                while tb is not None:
                    try:
                        tb.tb_frame.clear()
                        tb.tb_frame.f_locals
                    except RuntimeError:
                        # Ignore the exception raised if the frame is still executing.
                        pass
                    tb = tb.tb_next

            elif (2, 7, 0) <= sys.version_info < (3, 0, 0):
                sys.exc_clear()

            del tb

    def prepare_exception(self, exc, serializer=None):
        """Prepare exception for serialization."""
        serializer = self.serializer if serializer is None else serializer
        if serializer in EXCEPTION_ABLE_CODECS:
            return get_pickleable_exception(exc)
        exctype = type(exc)
        return {'exc_type': getattr(exctype, '__qualname__', exctype.__name__),
                'exc_message': ensure_serializable(exc.args, self.encode),
                'exc_module': exctype.__module__}

    def exception_to_python(self, exc):
        """Convert serialized exception to Python exception."""
        if exc:
            if not isinstance(exc, BaseException):