Combine multiple exceptions into a linked one

When multiple tasks running at the same time
throw exceptions previously we would not be
able to rethrow all the combined ones which
was suboptimal. Instead of doing that create
a combined linked exception that can retain
all of the exceptions that were thrown and
rethrow that in the situation where more than
one task fails.

Change-Id: I8f882e0d58caa189d6bff2e33b0bc30c4cee553d
This commit is contained in:
Joshua Harlow
2013-08-28 22:54:29 -07:00
committed by Joshua Harlow
parent ab9ca13055
commit b0fa3b2c9a
2 changed files with 37 additions and 5 deletions

View File

@@ -16,6 +16,10 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import StringIO
import traceback
class TaskFlowException(Exception): class TaskFlowException(Exception):
"""Base class for exceptions emitted from this library.""" """Base class for exceptions emitted from this library."""
@@ -27,6 +31,33 @@ class Duplicate(TaskFlowException):
pass pass
class LinkedException(TaskFlowException):
"""A linked chain of many exceptions."""
def __init__(self, message, cause, tb):
super(LinkedException, self).__init__(message)
self.cause = cause
self.tb = tb
self.next = None
@classmethod
def link(cls, exc_infos):
first = None
previous = None
for exc_info in exc_infos:
if not all(exc_info) or not len(exc_infos) == 3:
raise ValueError("Invalid exc_info")
buf = StringIO.StringIO()
traceback.print_exception(exc_info[0], exc_info[1], exc_info[2],
file=buf)
exc = cls(str(exc_info[1]), exc_info[1], buf.getvalue())
if previous is not None:
previous.next = exc
else:
first = exc
previous = exc
return first
class StorageError(TaskFlowException): class StorageError(TaskFlowException):
"""Raised when logbook can not be read/saved/deleted.""" """Raised when logbook can not be read/saved/deleted."""

View File

@@ -349,10 +349,11 @@ class Flow(flow.Flow):
except exc.InvalidStateException: except exc.InvalidStateException:
pass pass
finally: finally:
# TODO(harlowja): re-raise a combined exception when if len(failures) > 1:
# there are more than one failures?? exc_infos = [f.exc_info for f in failures]
for f in failures: raise exc.LinkedException.link(exc_infos)
if all(f.exc_info): else:
f = failures[0]
raise f.exc_info[0], f.exc_info[1], f.exc_info[2] raise f.exc_info[0], f.exc_info[1], f.exc_info[2]
def handle_results(): def handle_results():