1 | from __future__ import ( |
||
0 ignored issues
–
show
|
|||
2 | absolute_import, |
||
3 | division, |
||
4 | print_function |
||
5 | ) |
||
6 | |||
7 | import json |
||
8 | import logging |
||
9 | |||
10 | from .schema import ValidationError |
||
11 | from .state import State |
||
12 | from .step_results import ( |
||
13 | ActivityStepResult, |
||
14 | TemplatedStepResult, |
||
15 | ) |
||
16 | |||
17 | _LOGGER = logging.getLogger(__name__) |
||
18 | |||
19 | |||
20 | class StateMachine(object): |
||
0 ignored issues
–
show
This class should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. ![]() |
|||
21 | |||
22 | __slots__ = ('plan', 'state', '_event_ids') |
||
23 | |||
24 | def __init__(self, plan): |
||
25 | self.plan = plan |
||
26 | self.state = None |
||
27 | self._event_ids = {} |
||
28 | |||
29 | ########################################################################### |
||
30 | # Accessors |
||
31 | @property |
||
32 | def is_failed(self): |
||
0 ignored issues
–
show
This method should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. ![]() |
|||
33 | return self.state.is_in_state('failed') |
||
34 | |||
35 | @property |
||
36 | def is_succeeded(self): |
||
0 ignored issues
–
show
This method should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. ![]() |
|||
37 | return self.state.is_in_state('succeeded') |
||
38 | |||
39 | ########################################################################### |
||
40 | def eval(self, events): |
||
0 ignored issues
–
show
This method should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. ![]() |
|||
41 | # First clear the state |
||
42 | self.state = State() |
||
43 | self._event_ids.clear() |
||
44 | |||
45 | # Inject a load plan event |
||
46 | self._run_event({'eventId': 0, 'eventType': 'PlanLoad'}) |
||
47 | |||
48 | # Then, replay the state from the events |
||
49 | for event in events: |
||
50 | results = self._run_event(event) |
||
51 | |||
52 | _LOGGER.info('State replayed from events: %r', self.state) |
||
53 | return results |
||
54 | |||
55 | ########################################################################### |
||
56 | def _run_event(self, event): |
||
57 | """Process a given event and return a list of results. |
||
58 | """ |
||
59 | _LOGGER.info('Processing event %r', event['eventType']) |
||
60 | |||
61 | handler_fun = getattr( |
||
62 | self, |
||
63 | 'EVENT_%s' % event['eventType'], |
||
64 | self.__ev_abort |
||
65 | ) |
||
66 | handler_fun(event) |
||
67 | |||
68 | # If there is nothing left to do, stop here |
||
69 | if self.state.is_in_state('completed'): |
||
70 | return [] |
||
71 | |||
72 | _LOGGER.info('Running all "ready" steps') |
||
73 | ready_steps = self.state.step_next() |
||
74 | _LOGGER.info('Next steps: %r', ready_steps) |
||
75 | |||
76 | results = [] |
||
77 | for step in ready_steps: |
||
78 | step_result = step.run() |
||
79 | _LOGGER.info('step_result: %r', step_result) |
||
80 | if isinstance(step_result, ActivityStepResult): |
||
81 | results.append(step_result) |
||
82 | |||
83 | elif isinstance(step_result, TemplatedStepResult): |
||
84 | #results.append(step_result) |
||
85 | raise Exception('Not implemented') |
||
86 | |||
87 | _LOGGER.info('Results: %r', results) |
||
88 | return results |
||
89 | |||
90 | ########################################################################### |
||
91 | # Events and handlers |
||
92 | def __ev_load(self, event): |
||
0 ignored issues
–
show
This method should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. ![]() |
|||
93 | # Create loading time steps from the plan |
||
94 | with self.state(event['eventId']): |
||
95 | # Import all predefined steps from the plan |
||
96 | for step in self.plan.steps: |
||
97 | self.state.step_insert(step) |
||
98 | |||
99 | def __ev_skip(self, event): |
||
0 ignored issues
–
show
This method should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. ![]() This method could be written as a function/class method.
If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example class Foo:
def some_method(self, x, y):
return x + y;
could be written as class Foo:
@classmethod
def some_method(cls, x, y):
return x + y;
![]() |
|||
100 | _LOGGER.info('Skipping event: %r', event['eventType']) |
||
101 | |||
102 | def __ev_abort(self, event): |
||
0 ignored issues
–
show
This method should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. ![]() |
|||
103 | _LOGGER.error('Unknown event: %r', event) |
||
104 | with self.state(event['eventId']): |
||
105 | # Set the input |
||
106 | self.state.set_abort() |
||
107 | |||
108 | def __ev_start(self, event): |
||
109 | """Import input data""" |
||
110 | _LOGGER.info('%r', event) |
||
111 | start_attrs = event['workflowExecutionStartedEventAttributes'] |
||
112 | # Note that if no input was provided, the 'input' key will not be there |
||
113 | wf_input = start_attrs.get('input', 'null') |
||
114 | try: |
||
115 | input_data = json.loads(wf_input) |
||
116 | self.plan.check_input(input_data) |
||
117 | |||
118 | except (ValueError, ValidationError): |
||
119 | _LOGGER.exception('Invalid workflow input: %r', wf_input) |
||
120 | # We cannot do anything, just abort |
||
121 | with self.state(event['eventId']): |
||
122 | self.state.set_abort() |
||
123 | return |
||
124 | |||
125 | with self.state(event['eventId']): |
||
126 | # Set the input |
||
127 | self.state.set_input(input_data) |
||
128 | |||
129 | def __ev_scheduled(self, event): |
||
130 | """Record the eventId associated with activities we scheduled.""" |
||
131 | _LOGGER.info('%r', event) |
||
132 | step_name = event['activityTaskScheduledEventAttributes']['activityId'] |
||
133 | event_id = event['eventId'] |
||
134 | |||
135 | with self.state(event['eventId']): |
||
136 | self.state.step_update(step_name, 'running') |
||
137 | |||
138 | _LOGGER.info('Associating step %r with event_id %r', |
||
139 | step_name, event_id) |
||
140 | self._event_ids[event_id] = step_name |
||
141 | |||
142 | def __ev_completed(self, event): |
||
0 ignored issues
–
show
This method should have a docstring.
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods: class SomeClass:
def some_method(self):
"""Do x and return foo."""
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions. ![]() |
|||
143 | _LOGGER.info('%r', event) |
||
144 | completed_event = event['activityTaskCompletedEventAttributes'] |
||
145 | output_json = completed_event.get('result', 'null') |
||
146 | output = json.loads(output_json) |
||
147 | sched_event_id = completed_event['scheduledEventId'] |
||
148 | step_name = self._event_ids[sched_event_id] |
||
149 | with self.state(event['eventId']): |
||
150 | self.state.step_update(step_name, 'succeeded', output) |
||
151 | |||
152 | EVENT_PlanLoad = __ev_load |
||
153 | EVENT_WorkflowExecutionStarted = __ev_start |
||
154 | EVENT_DecisionTaskScheduled = __ev_skip |
||
155 | EVENT_DecisionTaskStarted = __ev_skip |
||
156 | EVENT_DecisionTaskCompleted = __ev_skip |
||
157 | EVENT_DecisionTaskTimedOut = __ev_skip |
||
158 | EVENT_ActivityTaskScheduled = __ev_scheduled |
||
159 | EVENT_ActivityTaskStarted = __ev_skip |
||
160 | EVENT_ActivityTaskCompleted = __ev_completed |
||
161 |
The coding style of this project requires that you add a docstring to this code element. Below, you find an example for methods:
If you would like to know more about docstrings, we recommend to read PEP-257: Docstring Conventions.