| Index: dashboard/dashboard/pinpoint/models/quest/execution.py
|
| diff --git a/dashboard/dashboard/pinpoint/models/quest/execution.py b/dashboard/dashboard/pinpoint/models/quest/execution.py
|
| index 77a9636558bfcd3579a9d459b356ccb546adb557..d521f9d7e8321da113291da3fe80feb5cd45262f 100644
|
| --- a/dashboard/dashboard/pinpoint/models/quest/execution.py
|
| +++ b/dashboard/dashboard/pinpoint/models/quest/execution.py
|
| @@ -21,13 +21,13 @@ class Execution(object):
|
|
|
| def __init__(self):
|
| self._completed = False
|
| - self._failed = False
|
| + self._exception = None
|
| self._result_values = ()
|
| self._result_arguments = {}
|
|
|
| @property
|
| def completed(self):
|
| - """Returns True iff the Execution is completed. Otherwise, it's in progress.
|
| + """Returns True iff the Execution is completed. Otherwise, it's running.
|
|
|
| This accessor doesn't contact external servers. Call Poll() to update the
|
| Execution's completed status.
|
| @@ -41,7 +41,12 @@ class Execution(object):
|
| This accessor doesn't contact external servers. Call Poll() to update the
|
| Execution's failed status.
|
| """
|
| - return self._failed
|
| + return bool(self._exception)
|
| +
|
| + @property
|
| + def exception(self):
|
| + """Returns the stack trace if the Execution failed, or None otherwise."""
|
| + return self._exception
|
|
|
| @property
|
| def result_values(self):
|
| @@ -67,8 +72,9 @@ class Execution(object):
|
|
|
| def AsDict(self):
|
| d = {
|
| - 'result_arguments': self.result_arguments if self.completed else {},
|
| - 'result_values': self.result_values if self.completed else None,
|
| + 'exception': self._exception,
|
| + 'result_arguments': self._result_arguments,
|
| + 'result_values': self._result_values,
|
| }
|
| d.update(self._AsDict())
|
| return d
|
| @@ -77,7 +83,15 @@ class Execution(object):
|
| raise NotImplementedError()
|
|
|
| def Poll(self):
|
| - """Update the Execution status."""
|
| + """Update the Execution status, with error handling.
|
| +
|
| + Pinpoint has two kinds of errors: Job-level errors, which are fatal and
|
| + cause the Job to fail; and Execution-level errors, which only cause that
|
| + one execution to fail. If something might pass at one commit and fail at
|
| + another, it should be an Execution-level error. The type of Exception
|
| + indicates the error level. StandardErrors are Job-level and all other
|
| + errors are Execution-level.
|
| + """
|
| assert not self.completed
|
|
|
| try:
|
| @@ -90,19 +104,12 @@ class Execution(object):
|
| # We allow broad exception handling here, because we log the exception and
|
| # display it in the UI.
|
| self._completed = True
|
| - self._failed = True
|
| - # TODO: If the Execution normally returns a number, it will be a string in
|
| - # this case. This works fine in CPython 2.0, where any number is less than
|
| - # any string. But it may not work in other Python implementations. The
|
| - # same is true for "None" below.
|
| - self._result_values = (traceback.format_exc(),)
|
| -
|
| + self._exception = traceback.format_exc()
|
|
|
| def _Poll(self):
|
| raise NotImplementedError()
|
|
|
| - def _Complete(self, result_values=None, result_arguments=None):
|
| + def _Complete(self, result_values=(), result_arguments=None):
|
| self._completed = True
|
| - self._failed = False
|
| - self._result_values = result_values or (None,)
|
| + self._result_values = result_values
|
| self._result_arguments = result_arguments or {}
|
|
|