Add retry to execution graph
Change-Id: I8d9a608257fee66c462bd45150383774a93e90b0
This commit is contained in:
		| @@ -22,6 +22,7 @@ from taskflow import exceptions as exc | |||||||
| from taskflow.patterns import graph_flow as gf | from taskflow.patterns import graph_flow as gf | ||||||
| from taskflow.patterns import linear_flow as lf | from taskflow.patterns import linear_flow as lf | ||||||
| from taskflow.patterns import unordered_flow as uf | from taskflow.patterns import unordered_flow as uf | ||||||
|  | from taskflow import retry | ||||||
|  |  | ||||||
| from taskflow import test | from taskflow import test | ||||||
| from taskflow.tests import utils as t_utils | from taskflow.tests import utils as t_utils | ||||||
| @@ -183,3 +184,110 @@ class FlattenTest(test.TestCase): | |||||||
|         self.assertRaisesRegexp(exc.InvariantViolation, |         self.assertRaisesRegexp(exc.InvariantViolation, | ||||||
|                                 '^Tasks with duplicate names', |                                 '^Tasks with duplicate names', | ||||||
|                                 f_utils.flatten, flo) |                                 f_utils.flatten, flo) | ||||||
|  |  | ||||||
|  |     def test_flatten_retry_in_linear_flow(self): | ||||||
|  |         flo = lf.Flow("test", retry.AlwaysRevert("c")) | ||||||
|  |         g = f_utils.flatten(flo) | ||||||
|  |         self.assertEqual(1, len(g)) | ||||||
|  |         self.assertEqual(0, g.number_of_edges()) | ||||||
|  |  | ||||||
|  |     def test_flatten_retry_in_unordered_flow(self): | ||||||
|  |         flo = uf.Flow("test", retry.AlwaysRevert("c")) | ||||||
|  |         g = f_utils.flatten(flo) | ||||||
|  |         self.assertEqual(1, len(g)) | ||||||
|  |         self.assertEqual(0, g.number_of_edges()) | ||||||
|  |  | ||||||
|  |     def test_flatten_retry_in_graph_flow(self): | ||||||
|  |         flo = gf.Flow("test", retry.AlwaysRevert("c")) | ||||||
|  |         g = f_utils.flatten(flo) | ||||||
|  |         self.assertEqual(1, len(g)) | ||||||
|  |         self.assertEqual(0, g.number_of_edges()) | ||||||
|  |  | ||||||
|  |     def test_flatten_retry_in_nested_flows(self): | ||||||
|  |         c1 = retry.AlwaysRevert("c1") | ||||||
|  |         c2 = retry.AlwaysRevert("c2") | ||||||
|  |         flo = lf.Flow("test", c1).add(lf.Flow("test2", c2)) | ||||||
|  |         g = f_utils.flatten(flo) | ||||||
|  |         self.assertEqual(2, len(g)) | ||||||
|  |         self.assertEqual(1, g.number_of_edges()) | ||||||
|  |         self.assertEqual(set([c1]), | ||||||
|  |                          set(g_utils.get_no_predecessors(g))) | ||||||
|  |         self.assertEqual(set([c2]), | ||||||
|  |                          set(g_utils.get_no_successors(g))) | ||||||
|  |  | ||||||
|  |     def test_flatten_retry_in_linear_flow_with_tasks(self): | ||||||
|  |         c = retry.AlwaysRevert("c") | ||||||
|  |         a, b = _make_many(2) | ||||||
|  |         flo = lf.Flow("test", c).add(a, b) | ||||||
|  |         g = f_utils.flatten(flo) | ||||||
|  |         self.assertEqual(3, len(g)) | ||||||
|  |         self.assertEqual(2, g.number_of_edges()) | ||||||
|  |         self.assertEqual(set([c]), | ||||||
|  |                          set(g_utils.get_no_predecessors(g))) | ||||||
|  |         self.assertEqual(set([b]), | ||||||
|  |                          set(g_utils.get_no_successors(g))) | ||||||
|  |         self.assertEqual(c, g.node[a]['retry']) | ||||||
|  |         self.assertEqual(c, g.node[b]['retry']) | ||||||
|  |  | ||||||
|  |     def test_flatten_retry_in_unordered_flow_with_tasks(self): | ||||||
|  |         c = retry.AlwaysRevert("c") | ||||||
|  |         a, b = _make_many(2) | ||||||
|  |         flo = uf.Flow("test", c).add(a, b) | ||||||
|  |         g = f_utils.flatten(flo) | ||||||
|  |         self.assertEqual(3, len(g)) | ||||||
|  |         self.assertEqual(2, g.number_of_edges()) | ||||||
|  |         self.assertEqual(set([c]), | ||||||
|  |                          set(g_utils.get_no_predecessors(g))) | ||||||
|  |         self.assertEqual(set([a, b]), | ||||||
|  |                          set(g_utils.get_no_successors(g))) | ||||||
|  |         self.assertEqual(c, g.node[a]['retry']) | ||||||
|  |         self.assertEqual(c, g.node[b]['retry']) | ||||||
|  |  | ||||||
|  |     def test_flatten_retry_in_graph_flow_with_tasks(self): | ||||||
|  |         c = retry.AlwaysRevert("cp") | ||||||
|  |         a, b, d = _make_many(3) | ||||||
|  |         flo = gf.Flow("test", c).add(a, b, d).link(b, d) | ||||||
|  |         g = f_utils.flatten(flo) | ||||||
|  |         self.assertEqual(4, len(g)) | ||||||
|  |         self.assertEqual(3, g.number_of_edges()) | ||||||
|  |         self.assertEqual(set([c]), | ||||||
|  |                          set(g_utils.get_no_predecessors(g))) | ||||||
|  |         self.assertEqual(set([a, d]), | ||||||
|  |                          set(g_utils.get_no_successors(g))) | ||||||
|  |         self.assertEqual(c, g.node[a]['retry']) | ||||||
|  |         self.assertEqual(c, g.node[b]['retry']) | ||||||
|  |         self.assertEqual(c, g.node[d]['retry']) | ||||||
|  |  | ||||||
|  |     def test_flatten_retries_hierarchy(self): | ||||||
|  |         c1 = retry.AlwaysRevert("cp1") | ||||||
|  |         c2 = retry.AlwaysRevert("cp2") | ||||||
|  |         a, b, c, d = _make_many(4) | ||||||
|  |         flo = lf.Flow("test", c1).add( | ||||||
|  |             a, | ||||||
|  |             lf.Flow("test", c2).add(b, c), | ||||||
|  |             d) | ||||||
|  |         g = f_utils.flatten(flo) | ||||||
|  |         self.assertEqual(6, len(g)) | ||||||
|  |         self.assertEqual(5, g.number_of_edges()) | ||||||
|  |         self.assertEqual(c1, g.node[a]['retry']) | ||||||
|  |         self.assertEqual(c1, g.node[d]['retry']) | ||||||
|  |         self.assertEqual(c2, g.node[b]['retry']) | ||||||
|  |         self.assertEqual(c2, g.node[c]['retry']) | ||||||
|  |         self.assertEqual(c1, g.node[c2]['retry']) | ||||||
|  |         self.assertEqual(None, g.node[c1].get('retry')) | ||||||
|  |  | ||||||
|  |     def test_flatten_retry_subflows_hierarchy(self): | ||||||
|  |         c1 = retry.AlwaysRevert("cp1") | ||||||
|  |         a, b, c, d = _make_many(4) | ||||||
|  |         flo = lf.Flow("test", c1).add( | ||||||
|  |             a, | ||||||
|  |             lf.Flow("test").add(b, c), | ||||||
|  |             d) | ||||||
|  |         g = f_utils.flatten(flo) | ||||||
|  |         self.assertEqual(5, len(g)) | ||||||
|  |         self.assertEqual(4, g.number_of_edges()) | ||||||
|  |         self.assertEqual(c1, g.node[a]['retry']) | ||||||
|  |         self.assertEqual(c1, g.node[d]['retry']) | ||||||
|  |         self.assertEqual(c1, g.node[b]['retry']) | ||||||
|  |         self.assertEqual(c1, g.node[c]['retry']) | ||||||
|  |         self.assertEqual(None, g.node[c1].get('retry')) | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ import threading | |||||||
| import networkx as nx | import networkx as nx | ||||||
|  |  | ||||||
| from taskflow import exceptions | from taskflow import exceptions | ||||||
|  | from taskflow import flow | ||||||
| from taskflow.patterns import graph_flow as gf | from taskflow.patterns import graph_flow as gf | ||||||
| from taskflow.patterns import linear_flow as lf | from taskflow.patterns import linear_flow as lf | ||||||
| from taskflow.patterns import unordered_flow as uf | from taskflow.patterns import unordered_flow as uf | ||||||
| @@ -87,6 +88,21 @@ class Flattener(object): | |||||||
|         else: |         else: | ||||||
|             return None |             return None | ||||||
|  |  | ||||||
|  |     def _connect_retry(self, retry, graph): | ||||||
|  |         graph.add_node(retry) | ||||||
|  |         # All graph nodes that has not predecessors should be depended on its | ||||||
|  |         # retry | ||||||
|  |         for n in gu.get_no_predecessors(graph): | ||||||
|  |             if n != retry: | ||||||
|  |                 # modified that the same copy isn't modified. | ||||||
|  |                 graph.add_edge(retry, n, FLATTEN_EDGE_DATA.copy()) | ||||||
|  |  | ||||||
|  |         # Add link to retry for each node of subgraph that hasn't | ||||||
|  |         # a parent retry | ||||||
|  |         for n in graph.nodes_iter(): | ||||||
|  |             if n != retry and 'retry' not in graph.node[n]: | ||||||
|  |                 graph.add_node(n, {'retry': retry}) | ||||||
|  |  | ||||||
|     def _flatten_linear(self, flow): |     def _flatten_linear(self, flow): | ||||||
|         """Flattens a linear flow.""" |         """Flattens a linear flow.""" | ||||||
|         graph = nx.DiGraph(name=flow.name) |         graph = nx.DiGraph(name=flow.name) | ||||||
| @@ -154,6 +170,8 @@ class Flattener(object): | |||||||
|  |  | ||||||
|     def _post_item_flatten(self, item, graph): |     def _post_item_flatten(self, item, graph): | ||||||
|         """Called before a item is flattened; any post-flattening actions.""" |         """Called before a item is flattened; any post-flattening actions.""" | ||||||
|  |         if isinstance(item, flow.Flow) and item.retry: | ||||||
|  |             self._connect_retry(item.retry, graph) | ||||||
|         LOG.debug("Finished flattening '%s'", item) |         LOG.debug("Finished flattening '%s'", item) | ||||||
|         # NOTE(harlowja): this one can be expensive to calculate (especially |         # NOTE(harlowja): this one can be expensive to calculate (especially | ||||||
|         # the cycle detection), so only do it if we know debugging is enabled |         # the cycle detection), so only do it if we know debugging is enabled | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Anastasia Karpinska
					Anastasia Karpinska