From 5a32ffcfc32bc2476f9cf5b1dba5a54356c85baf Mon Sep 17 00:00:00 2001 From: Sebastian Wagner Date: Mon, 10 Feb 2020 14:20:25 +0100 Subject: [PATCH] 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 --- src/pybind/mgr/orchestrator.py | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/pybind/mgr/orchestrator.py b/src/pybind/mgr/orchestrator.py index a295f42c3aaa0..01409ccb07ce9 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 -- 2.39.5