mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-16 18:15:17 +00:00
fix: catch not Either type in workflow and return explicit error message (#13796)
This commit is contained in:
parent
8375f6e7a9
commit
d025e217d6
@ -11,6 +11,7 @@
|
|||||||
"""
|
"""
|
||||||
Each of the ingestion steps: Source, Sink, Stage,...
|
Each of the ingestion steps: Source, Sink, Stage,...
|
||||||
"""
|
"""
|
||||||
|
import inspect
|
||||||
import traceback
|
import traceback
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from typing import Iterable, Optional
|
from typing import Iterable, Optional
|
||||||
@ -79,6 +80,19 @@ class ReturnStep(Step, ABC):
|
|||||||
except WorkflowFatalError as err:
|
except WorkflowFatalError as err:
|
||||||
logger.error(f"Fatal error running step [{self}]: [{err}]")
|
logger.error(f"Fatal error running step [{self}]: [{err}]")
|
||||||
raise err
|
raise err
|
||||||
|
except AttributeError as exc:
|
||||||
|
error = (
|
||||||
|
f"Object type defined in `def _run()` "
|
||||||
|
f"{inspect.getsourcefile(self._run)} is not an Either: [{exc}]"
|
||||||
|
)
|
||||||
|
logger.warning(error)
|
||||||
|
self.status.failed(
|
||||||
|
StackTraceError(
|
||||||
|
name="Not an Either",
|
||||||
|
error=error,
|
||||||
|
stack_trace=traceback.format_exc(),
|
||||||
|
)
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
error = f"Unhandled exception during workflow processing: [{exc}]"
|
error = f"Unhandled exception during workflow processing: [{exc}]"
|
||||||
logger.warning(error)
|
logger.warning(error)
|
||||||
@ -121,6 +135,19 @@ class StageStep(Step, ABC):
|
|||||||
except WorkflowFatalError as err:
|
except WorkflowFatalError as err:
|
||||||
logger.error(f"Fatal error running step [{self}]: [{err}]")
|
logger.error(f"Fatal error running step [{self}]: [{err}]")
|
||||||
raise err
|
raise err
|
||||||
|
except AttributeError as exc:
|
||||||
|
error = (
|
||||||
|
f"Object type defined in `def _run()` "
|
||||||
|
f"{inspect.getsourcefile(self._run)} is not an Either: [{exc}]"
|
||||||
|
)
|
||||||
|
logger.warning(error)
|
||||||
|
self.status.failed(
|
||||||
|
StackTraceError(
|
||||||
|
name="Not an Either",
|
||||||
|
error=error,
|
||||||
|
stack_trace=traceback.format_exc(),
|
||||||
|
)
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
error = f"Unhandled exception during workflow processing: [{exc}]"
|
error = f"Unhandled exception during workflow processing: [{exc}]"
|
||||||
logger.warning(error)
|
logger.warning(error)
|
||||||
@ -157,6 +184,19 @@ class IterStep(Step, ABC):
|
|||||||
except WorkflowFatalError as err:
|
except WorkflowFatalError as err:
|
||||||
logger.error(f"Fatal error running step [{self}]: [{err}]")
|
logger.error(f"Fatal error running step [{self}]: [{err}]")
|
||||||
raise err
|
raise err
|
||||||
|
except AttributeError as exc:
|
||||||
|
error = (
|
||||||
|
f"Object type defined in `def _iter()` "
|
||||||
|
f"{inspect.getsourcefile(self._iter)} is not an Either: [{exc}]"
|
||||||
|
)
|
||||||
|
logger.warning(error)
|
||||||
|
self.status.failed(
|
||||||
|
StackTraceError(
|
||||||
|
name="Not an Either",
|
||||||
|
error=error,
|
||||||
|
stack_trace=traceback.format_exc(),
|
||||||
|
)
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
error = f"Encountered exception running step [{self}]: [{exc}]"
|
error = f"Encountered exception running step [{self}]: [{exc}]"
|
||||||
logger.warning(error)
|
logger.warning(error)
|
||||||
|
|||||||
@ -62,6 +62,27 @@ class SimpleSource(WorkflowSource):
|
|||||||
yield Either(right=element)
|
yield Either(right=element)
|
||||||
|
|
||||||
|
|
||||||
|
class BrokenSource(WorkflowSource):
|
||||||
|
"""Source not returning an Either"""
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
"""Nothing to do"""
|
||||||
|
|
||||||
|
def test_connection(self) -> None:
|
||||||
|
"""Nothing to do"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create(cls, _: dict, __: OpenMetadataConnection) -> "SimpleSource":
|
||||||
|
return cls()
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
"""Nothing to do"""
|
||||||
|
|
||||||
|
def _iter(self, *args, **kwargs) -> Iterable[int]:
|
||||||
|
for element in range(0, 5):
|
||||||
|
yield int(element)
|
||||||
|
|
||||||
|
|
||||||
class SimpleSink(Sink):
|
class SimpleSink(Sink):
|
||||||
"""
|
"""
|
||||||
Simple Sink for testing
|
Simple Sink for testing
|
||||||
@ -94,6 +115,17 @@ class SimpleWorkflow(BaseWorkflow):
|
|||||||
self.steps: Tuple[Step] = (SimpleSink(),)
|
self.steps: Tuple[Step] = (SimpleSink(),)
|
||||||
|
|
||||||
|
|
||||||
|
class BrokenWorkflow(BaseWorkflow):
|
||||||
|
"""
|
||||||
|
Simple Workflow for testing
|
||||||
|
"""
|
||||||
|
|
||||||
|
def set_steps(self):
|
||||||
|
self.source = BrokenSource()
|
||||||
|
|
||||||
|
self.steps: Tuple[Step] = (SimpleSink(),)
|
||||||
|
|
||||||
|
|
||||||
# Pass only the required details so that the workflow can be initialized
|
# Pass only the required details so that the workflow can be initialized
|
||||||
config = OpenMetadataWorkflowConfig(
|
config = OpenMetadataWorkflowConfig(
|
||||||
source=Source(
|
source=Source(
|
||||||
@ -119,6 +151,7 @@ class TestBaseWorkflow(TestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
workflow = SimpleWorkflow(config=config)
|
workflow = SimpleWorkflow(config=config)
|
||||||
|
broken_workflow = BrokenWorkflow(config=config)
|
||||||
|
|
||||||
@pytest.mark.order(1)
|
@pytest.mark.order(1)
|
||||||
def test_workflow_executes(self):
|
def test_workflow_executes(self):
|
||||||
@ -143,3 +176,17 @@ class TestBaseWorkflow(TestCase):
|
|||||||
def test_workflow_raise_status(self):
|
def test_workflow_raise_status(self):
|
||||||
# We catch the error on the Sink
|
# We catch the error on the Sink
|
||||||
self.assertRaises(WorkflowExecutionError, self.workflow.raise_from_status)
|
self.assertRaises(WorkflowExecutionError, self.workflow.raise_from_status)
|
||||||
|
|
||||||
|
def test_broken_workflow(self):
|
||||||
|
"""test our broken workflow return expected exc"""
|
||||||
|
self.broken_workflow.execute()
|
||||||
|
self.assertRaises(
|
||||||
|
WorkflowExecutionError, self.broken_workflow.raise_from_status
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
self.broken_workflow.source.status.failures[0].name, "Not an Either"
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
"workflow/test_base_workflow.py"
|
||||||
|
in self.broken_workflow.source.status.failures[0].error
|
||||||
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user