From: Sebastian Wagner Date: Mon, 10 Feb 2020 13:20:25 +0000 (+0100) Subject: mgr/orchestrator: Use `pickle` to pass exceptions across sub-interpreters X-Git-Tag: v15.1.1~480^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=refs%2Fpull%2F33179%2Fhead;p=ceph.git mgr/orchestrator: Use `pickle` to pass exceptions across sub-interpreters `copy.deepcopy` doesn't work to cross sub-interpreter boundaries. Fixes: https://tracker.ceph.com/issues/43913 Signed-off-by: Sebastian Wagner --- diff --git a/src/pybind/mgr/orchestrator.py b/src/pybind/mgr/orchestrator.py index a295f42c3aaa..01409ccb07ce 100644 --- a/src/pybind/mgr/orchestrator.py +++ b/src/pybind/mgr/orchestrator.py @@ -7,6 +7,7 @@ Please see the ceph-mgr module developer's guide for more information. import copy import functools import logging +import pickle import sys import time from collections import namedtuple @@ -202,6 +203,23 @@ class _Promise(object): # T instead of (T -> r) -> r. Therefore we need to store the first promise here. self._first_promise = _first_promise or self # type: '_Promise' + @property + def _exception(self): + # type: () -> Optional[Exception] + return getattr(self, '_exception_', None) + + @_exception.setter + def _exception(self, e): + self._exception_ = e + self._serialized_exception_ = pickle.dumps(e) if e is not None else None + + @property + def _serialized_exception(self): + # type: () -> Optional[bytes] + return getattr(self, '_serialized_exception_', None) + + + @property def _on_complete(self): # type: () -> Optional[Callable] @@ -568,6 +586,11 @@ class Completion(_Promise): # type: () -> Optional[Exception] return self._last_promise()._exception + @property + def serialized_exception(self): + # type: () -> Optional[bytes] + return self._last_promise()._serialized_exception + @property def has_result(self): # type: () -> bool @@ -631,9 +654,9 @@ def raise_if_exception(c): :raises OrchestratorError: Some user error or a config error. :raises Exception: Some internal error """ - if c.exception is not None: + if c.serialized_exception is not None: try: - e = copy.deepcopy(c.exception) + e = pickle.loads(c.serialized_exception) except (KeyError, AttributeError): raise Exception('{}: {}'.format(type(c.exception), c.exception)) raise e