stepfunction 0.0.5__tar.gz → 0.0.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {stepfunction-0.0.5/src/StepFunction.egg-info → stepfunction-0.0.7}/PKG-INFO +1 -1
- {stepfunction-0.0.5 → stepfunction-0.0.7}/pyproject.toml +1 -1
- {stepfunction-0.0.5 → stepfunction-0.0.7/src/StepFunction.egg-info}/PKG-INFO +1 -1
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/core/step_function/step_function.py +85 -49
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/core/visualizer/visualizer.py +4 -6
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/exceptions/step_errors.py +1 -1
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/steps/retry_step.py +12 -2
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/steps/timeout_step.py +4 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/steps/wait_step.py +4 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/types/step_types.py +2 -2
- {stepfunction-0.0.5 → stepfunction-0.0.7}/LICENSE +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/README.md +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/setup.cfg +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/StepFunction.egg-info/SOURCES.txt +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/StepFunction.egg-info/dependency_links.txt +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/StepFunction.egg-info/requires.txt +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/StepFunction.egg-info/top_level.txt +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/constants/__init__.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/constants/enums.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/constants/visualizer.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/core/step_function/__init__.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/core/visualizer/__init__.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/exceptions/__init__.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/steps/__init__.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/steps/base/__init__.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/steps/base/base_step.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/steps/exceptions/__init__.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/steps/exceptions/step_exceptions.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/types/__init__.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/types/visualizer_types.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/utils/__init__.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/utils/constants.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/utils/logger.py +0 -0
- {stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/utils/utils.py +0 -0
{stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/core/step_function/step_function.py
RENAMED
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
Author: Vineeth Penugonda
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
from asyncio import
|
|
7
|
-
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
6
|
+
from asyncio import gather, get_running_loop
|
|
8
7
|
from inspect import iscoroutinefunction
|
|
9
|
-
from typing import Any, Callable, Dict, Optional, Union
|
|
8
|
+
from typing import Any, Callable, Dict, Optional, Union, cast
|
|
10
9
|
|
|
11
10
|
from stepfunction.constants.enums import StepFunctionStatus
|
|
12
11
|
from stepfunction.exceptions.step_errors import (
|
|
@@ -34,7 +33,7 @@ class StepFunction:
|
|
|
34
33
|
|
|
35
34
|
Properties:
|
|
36
35
|
name (str): The name of the step function.
|
|
37
|
-
steps (StepParams): A dictionary containing the steps of the workflow.
|
|
36
|
+
steps (Dict[str, StepParams]): A dictionary containing the steps of the workflow.
|
|
38
37
|
last_result (Any): The result of the last step.
|
|
39
38
|
context (Dict[str, Any]): Stores step names and results, including exceptions if any occur.
|
|
40
39
|
status (StepFunctionStatus): The current status of the workflow. Possible values are:
|
|
@@ -53,6 +52,10 @@ class StepFunction:
|
|
|
53
52
|
add_sub_step_function(name, sub_step_function, next_step=None, on_failure=None):
|
|
54
53
|
Add a sub-step function to be executed as a step.
|
|
55
54
|
|
|
55
|
+
validate():
|
|
56
|
+
Validate the workflow configuration. Raises ValueError if the start step is not set
|
|
57
|
+
or if any next_step or on_failure reference an unknown step.
|
|
58
|
+
|
|
56
59
|
execute(initial_input=None):
|
|
57
60
|
Execute the workflow starting from the specified start step. This will run each step in sequence or in parallel,
|
|
58
61
|
depending on the step configuration.
|
|
@@ -91,11 +94,11 @@ class StepFunction:
|
|
|
91
94
|
await step_function.execute()
|
|
92
95
|
|
|
93
96
|
Parallel Example:
|
|
94
|
-
step_function.add_step("Step1", func1,
|
|
97
|
+
step_function.add_step("Step1", func1, next_step="ParallelStep")
|
|
95
98
|
step_function.add_step("ParallelStep", {
|
|
96
99
|
"task1": func2,
|
|
97
100
|
"task2": func3
|
|
98
|
-
},
|
|
101
|
+
}, parallel=True)
|
|
99
102
|
|
|
100
103
|
Sub-step function example:
|
|
101
104
|
sub_step_function = StepFunction("SubStepFunction")
|
|
@@ -110,11 +113,13 @@ class StepFunction:
|
|
|
110
113
|
def __init__(self, name: str):
|
|
111
114
|
self.__name = name # Name of the step function
|
|
112
115
|
|
|
113
|
-
self.__steps: StepParams = {} # Steps of the workflow
|
|
116
|
+
self.__steps: Dict[str, StepParams] = {} # Steps of the workflow
|
|
114
117
|
self.__current_step = None # The current step being executed
|
|
115
118
|
|
|
116
119
|
self.__last_result = None # To hold the result of the last step
|
|
117
|
-
self.__context
|
|
120
|
+
self.__context: Dict[
|
|
121
|
+
str, Any
|
|
122
|
+
] = {} # To hold the step names and results of those steps
|
|
118
123
|
|
|
119
124
|
# Status of the step function
|
|
120
125
|
self.__status: StepFunctionStatus = StepFunctionStatus.INITIALIZED
|
|
@@ -131,7 +136,7 @@ class StepFunction:
|
|
|
131
136
|
func: Union[Callable[[Any], Any], Dict[str, Callable[[Any], Any]], BaseStep],
|
|
132
137
|
next_step: Optional[str] = None,
|
|
133
138
|
on_failure: Optional[str] = None,
|
|
134
|
-
branch: Optional[Dict[Any, str]] = None,
|
|
139
|
+
branch: Optional[Union[Dict[Any, str], Callable[[Any], str]]] = None,
|
|
135
140
|
parallel: bool = False,
|
|
136
141
|
stop_on_failure: bool = False,
|
|
137
142
|
):
|
|
@@ -140,6 +145,12 @@ class StepFunction:
|
|
|
140
145
|
if name in self.__steps:
|
|
141
146
|
raise ValueError(f"Step '{name}' already exists in steps")
|
|
142
147
|
|
|
148
|
+
if branch is not None and next_step is not None:
|
|
149
|
+
raise ValueError(
|
|
150
|
+
f"Step '{name}' cannot have both 'branch' and 'next_step' set. "
|
|
151
|
+
"Use 'branch' to control routing or 'next_step' for a fixed transition, not both."
|
|
152
|
+
)
|
|
153
|
+
|
|
143
154
|
step_type = None
|
|
144
155
|
if isinstance(func, BaseStep):
|
|
145
156
|
step_type = func.step_type
|
|
@@ -152,6 +163,7 @@ class StepFunction:
|
|
|
152
163
|
"branch": branch,
|
|
153
164
|
"parallel": parallel,
|
|
154
165
|
"stop_on_failure": stop_on_failure,
|
|
166
|
+
"is_sub_step_function": False,
|
|
155
167
|
"step_type": step_type,
|
|
156
168
|
}
|
|
157
169
|
|
|
@@ -184,6 +196,7 @@ class StepFunction:
|
|
|
184
196
|
"parallel": False,
|
|
185
197
|
"stop_on_failure": False,
|
|
186
198
|
"is_sub_step_function": True,
|
|
199
|
+
"step_type": None,
|
|
187
200
|
}
|
|
188
201
|
|
|
189
202
|
def set_start_step(self, name: str):
|
|
@@ -193,9 +206,32 @@ class StepFunction:
|
|
|
193
206
|
|
|
194
207
|
self.__current_step = name
|
|
195
208
|
|
|
209
|
+
def validate(self):
|
|
210
|
+
"""Validate the workflow configuration before execution."""
|
|
211
|
+
|
|
212
|
+
if self.__current_step is None:
|
|
213
|
+
raise ValueError(
|
|
214
|
+
"No start step set. Call set_start_step() before executing the workflow."
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
for step_name, step in self.__steps.items():
|
|
218
|
+
if step["next_step"] is not None and step["next_step"] not in self.__steps:
|
|
219
|
+
raise ValueError(
|
|
220
|
+
f"Step '{step_name}' has unknown next_step '{step['next_step']}'."
|
|
221
|
+
)
|
|
222
|
+
if (
|
|
223
|
+
step["on_failure"] is not None
|
|
224
|
+
and step["on_failure"] not in self.__steps
|
|
225
|
+
):
|
|
226
|
+
raise ValueError(
|
|
227
|
+
f"Step '{step_name}' has unknown on_failure '{step['on_failure']}'."
|
|
228
|
+
)
|
|
229
|
+
|
|
196
230
|
async def execute(self, initial_input: Any = None):
|
|
197
231
|
"""Execute the workflow."""
|
|
198
232
|
|
|
233
|
+
self.validate()
|
|
234
|
+
|
|
199
235
|
self.__status = StepFunctionStatus.RUNNING
|
|
200
236
|
|
|
201
237
|
self.__logger.debug(
|
|
@@ -208,8 +244,9 @@ class StepFunction:
|
|
|
208
244
|
step = self.__steps[self.__current_step]
|
|
209
245
|
try:
|
|
210
246
|
if step["parallel"]:
|
|
211
|
-
results = self._execute_parallel(
|
|
212
|
-
|
|
247
|
+
results = await self._execute_parallel(
|
|
248
|
+
cast(Dict[str, Callable[[Any], Any]], step["func"]),
|
|
249
|
+
step["stop_on_failure"],
|
|
213
250
|
)
|
|
214
251
|
|
|
215
252
|
self.__last_result = results
|
|
@@ -219,7 +256,9 @@ class StepFunction:
|
|
|
219
256
|
f"Parallel step '{self.__current_step}' succeeded with results: {results}"
|
|
220
257
|
)
|
|
221
258
|
else:
|
|
222
|
-
result = await self._execute_step(
|
|
259
|
+
result = await self._execute_step(
|
|
260
|
+
cast(Callable[[Any], Any], step["func"]), self.__last_result
|
|
261
|
+
)
|
|
223
262
|
|
|
224
263
|
self.__last_result = result
|
|
225
264
|
self.__context[self.__current_step] = result
|
|
@@ -234,6 +273,17 @@ class StepFunction:
|
|
|
234
273
|
else:
|
|
235
274
|
next_step = step["branch"].get(self.__last_result)
|
|
236
275
|
|
|
276
|
+
if next_step is None:
|
|
277
|
+
self.__logger.warning(
|
|
278
|
+
f"Step '{self.__current_step}': branch did not resolve to a next step "
|
|
279
|
+
f"for result '{self.__last_result}'. Workflow will end."
|
|
280
|
+
)
|
|
281
|
+
elif next_step not in self.__steps:
|
|
282
|
+
self.__logger.warning(
|
|
283
|
+
f"Step '{self.__current_step}': branch resolved to '{next_step}' "
|
|
284
|
+
"which does not exist in steps. This will cause a failure."
|
|
285
|
+
)
|
|
286
|
+
|
|
237
287
|
self.__current_step = next_step or step["next_step"]
|
|
238
288
|
|
|
239
289
|
except Exception as exc:
|
|
@@ -241,7 +291,9 @@ class StepFunction:
|
|
|
241
291
|
f"Step '{self.__current_step}' failed. Exception: {exc}"
|
|
242
292
|
)
|
|
243
293
|
|
|
244
|
-
|
|
294
|
+
exc_value = exc.args[0] if exc.args else exc
|
|
295
|
+
|
|
296
|
+
self.__context[cast(str, self.__current_step)] = exc_value
|
|
245
297
|
|
|
246
298
|
if step["on_failure"]:
|
|
247
299
|
self.__logger.exception(
|
|
@@ -249,7 +301,7 @@ class StepFunction:
|
|
|
249
301
|
)
|
|
250
302
|
|
|
251
303
|
self.__current_step = step["on_failure"]
|
|
252
|
-
self.__last_result =
|
|
304
|
+
self.__last_result = exc_value
|
|
253
305
|
|
|
254
306
|
self.__status = StepFunctionStatus.FAILED
|
|
255
307
|
|
|
@@ -285,47 +337,31 @@ class StepFunction:
|
|
|
285
337
|
else:
|
|
286
338
|
return func(input_value)
|
|
287
339
|
|
|
288
|
-
def _execute_parallel(
|
|
340
|
+
async def _execute_parallel(
|
|
289
341
|
self, func_dict: Dict[str, Callable[[Any], Any]], stop_on_failure: bool = False
|
|
290
342
|
):
|
|
291
|
-
"""Execute the steps in parallel."""
|
|
343
|
+
"""Execute the steps in parallel without blocking the event loop."""
|
|
344
|
+
loop = get_running_loop()
|
|
292
345
|
results = {}
|
|
293
346
|
errors = []
|
|
294
|
-
should_stop_execution = False
|
|
295
347
|
|
|
296
|
-
def
|
|
348
|
+
async def _run_one(func: Callable[[Any], Any]) -> Any:
|
|
297
349
|
if iscoroutinefunction(func):
|
|
298
|
-
return
|
|
299
|
-
return func
|
|
300
|
-
|
|
301
|
-
with ThreadPoolExecutor() as executor:
|
|
302
|
-
futures = {
|
|
303
|
-
executor.submit(_run, func, self.__last_result): step_name
|
|
304
|
-
for step_name, func in func_dict.items()
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
for future in as_completed(futures):
|
|
308
|
-
step_name = futures[future]
|
|
350
|
+
return await func(self.__last_result)
|
|
351
|
+
return await loop.run_in_executor(None, func, self.__last_result)
|
|
309
352
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
result = future.result()
|
|
315
|
-
results[step_name] = result
|
|
316
|
-
except Exception as exc:
|
|
317
|
-
self.__logger.exception(
|
|
318
|
-
f"Parallel task '{step_name}' failed: {exc}"
|
|
319
|
-
)
|
|
320
|
-
|
|
321
|
-
results[step_name] = exc.args[0]
|
|
322
|
-
|
|
323
|
-
errors.append((step_name, exc))
|
|
353
|
+
task_results = await gather(
|
|
354
|
+
*[_run_one(func) for func in func_dict.values()],
|
|
355
|
+
return_exceptions=True,
|
|
356
|
+
)
|
|
324
357
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
358
|
+
for step_name, result in zip(func_dict.keys(), task_results):
|
|
359
|
+
if isinstance(result, Exception):
|
|
360
|
+
self.__logger.exception(f"Parallel task '{step_name}' failed: {result}")
|
|
361
|
+
results[step_name] = result.args[0] if result.args else result
|
|
362
|
+
errors.append((step_name, result))
|
|
363
|
+
else:
|
|
364
|
+
results[step_name] = result
|
|
329
365
|
|
|
330
366
|
if errors:
|
|
331
367
|
self.__logger.error(f"Some parallel tasks failed: {errors}")
|
|
@@ -374,7 +410,7 @@ class StepFunction:
|
|
|
374
410
|
@property
|
|
375
411
|
def steps(self):
|
|
376
412
|
"""Returns the steps of the step function."""
|
|
377
|
-
return self.__steps
|
|
413
|
+
return self.__steps.copy()
|
|
378
414
|
|
|
379
415
|
@property
|
|
380
416
|
def last_result(self):
|
|
@@ -384,7 +420,7 @@ class StepFunction:
|
|
|
384
420
|
@property
|
|
385
421
|
def context(self):
|
|
386
422
|
"""Returns the context of the step function."""
|
|
387
|
-
return self.__context
|
|
423
|
+
return self.__context.copy()
|
|
388
424
|
|
|
389
425
|
@property
|
|
390
426
|
def status(self):
|
|
@@ -4,6 +4,7 @@ Author: Vineeth Penugonda
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
from os import getcwd
|
|
7
|
+
from typing import Dict, Optional
|
|
7
8
|
|
|
8
9
|
from graphviz import Digraph
|
|
9
10
|
|
|
@@ -29,7 +30,7 @@ from stepfunction.types.visualizer_types import RenderStepFunctionParams
|
|
|
29
30
|
class Visualizer:
|
|
30
31
|
"""This class is responsible for visualizing the graph model."""
|
|
31
32
|
|
|
32
|
-
def __init__(self, graph_name: str, steps: StepParams = None):
|
|
33
|
+
def __init__(self, graph_name: str, steps: Optional[Dict[str, StepParams]] = None):
|
|
33
34
|
"""Initializes the visualizer."""
|
|
34
35
|
|
|
35
36
|
self.graph_name = graph_name
|
|
@@ -47,10 +48,7 @@ class Visualizer:
|
|
|
47
48
|
raise ValueError("No steps found to visualize.")
|
|
48
49
|
|
|
49
50
|
for step_name, step_info in self.__steps.items():
|
|
50
|
-
if
|
|
51
|
-
"is_sub_step_function" in step_info
|
|
52
|
-
and step_info["is_sub_step_function"]
|
|
53
|
-
):
|
|
51
|
+
if step_info["is_sub_step_function"]:
|
|
54
52
|
self.__dot.node(
|
|
55
53
|
step_name,
|
|
56
54
|
step_name,
|
|
@@ -100,7 +98,7 @@ class Visualizer:
|
|
|
100
98
|
if step_info["next_step"]:
|
|
101
99
|
self.__dot.edge(parallel_step_name, step_info["next_step"])
|
|
102
100
|
|
|
103
|
-
if step_info
|
|
101
|
+
if isinstance(step_info["branch"], dict):
|
|
104
102
|
for result, next_step in step_info["branch"].items():
|
|
105
103
|
self.__dot.edge(step_name, next_step, label=f"Branch: {result}")
|
|
106
104
|
|
|
@@ -9,6 +9,6 @@ class StepExecutionError(Exception):
|
|
|
9
9
|
class ParallelStepExecutionError(Exception):
|
|
10
10
|
"""Error raised when a parallel step fails."""
|
|
11
11
|
|
|
12
|
-
def __init__(self, exc: Exception):
|
|
12
|
+
def __init__(self, exc: list[tuple[str, Exception]]):
|
|
13
13
|
self.message = f"Parallel step generated an exception: {exc}"
|
|
14
14
|
super().__init__(self.message)
|
|
@@ -5,10 +5,11 @@ Author: Vineeth Penugonda
|
|
|
5
5
|
|
|
6
6
|
from asyncio import sleep
|
|
7
7
|
from inspect import iscoroutinefunction
|
|
8
|
-
from typing import Any, Callable
|
|
8
|
+
from typing import Any, Callable, Optional
|
|
9
9
|
|
|
10
10
|
from stepfunction.constants.enums import StepType
|
|
11
11
|
from stepfunction.steps.base import BaseStep
|
|
12
|
+
from stepfunction.utils.logger import setup_logger
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class RetryStep(BaseStep):
|
|
@@ -43,6 +44,7 @@ class RetryStep(BaseStep):
|
|
|
43
44
|
self.func = func
|
|
44
45
|
self.max_retries = max_retries
|
|
45
46
|
self.delay = delay
|
|
47
|
+
self.__logger = setup_logger(__name__)
|
|
46
48
|
|
|
47
49
|
def build(self) -> Callable[[Any], Any]:
|
|
48
50
|
"""Return an async function that retries ``func`` on failure."""
|
|
@@ -51,7 +53,10 @@ class RetryStep(BaseStep):
|
|
|
51
53
|
delay = self.delay
|
|
52
54
|
|
|
53
55
|
async def run(input_value: Any) -> Any:
|
|
54
|
-
|
|
56
|
+
self.__logger.debug(
|
|
57
|
+
f"RetryStep - executing with max_retries={max_retries}, delay={delay}s"
|
|
58
|
+
)
|
|
59
|
+
last_exc: Optional[Exception] = None
|
|
55
60
|
|
|
56
61
|
for attempt in range(max_retries + 1):
|
|
57
62
|
try:
|
|
@@ -60,9 +65,14 @@ class RetryStep(BaseStep):
|
|
|
60
65
|
return func(input_value)
|
|
61
66
|
except Exception as exc:
|
|
62
67
|
last_exc = exc
|
|
68
|
+
self.__logger.warning(
|
|
69
|
+
f"RetryStep - attempt {attempt + 1}/{max_retries + 1} failed: {exc}"
|
|
70
|
+
)
|
|
63
71
|
if attempt < max_retries:
|
|
72
|
+
self.__logger.debug(f"RetryStep - retrying in {delay}s")
|
|
64
73
|
await sleep(delay)
|
|
65
74
|
|
|
75
|
+
self.__logger.error(f"RetryStep - all {max_retries + 1} attempts exhausted")
|
|
66
76
|
raise last_exc
|
|
67
77
|
|
|
68
78
|
return run
|
|
@@ -11,6 +11,7 @@ from typing import Any, Callable
|
|
|
11
11
|
from stepfunction.constants.enums import StepType
|
|
12
12
|
from stepfunction.steps.base import BaseStep
|
|
13
13
|
from stepfunction.steps.exceptions import StepTimeoutError
|
|
14
|
+
from stepfunction.utils.logger import setup_logger
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class TimeoutStep(BaseStep):
|
|
@@ -39,6 +40,7 @@ class TimeoutStep(BaseStep):
|
|
|
39
40
|
|
|
40
41
|
self.func = func
|
|
41
42
|
self.timeout = timeout
|
|
43
|
+
self.__logger = setup_logger(__name__)
|
|
42
44
|
|
|
43
45
|
def build(self) -> Callable[[Any], Any]:
|
|
44
46
|
"""Return an async function that enforces a timeout on ``func``."""
|
|
@@ -46,6 +48,7 @@ class TimeoutStep(BaseStep):
|
|
|
46
48
|
timeout = self.timeout
|
|
47
49
|
|
|
48
50
|
async def run(input_value: Any) -> Any:
|
|
51
|
+
self.__logger.debug(f"TimeoutStep - executing with timeout of {timeout}s")
|
|
49
52
|
try:
|
|
50
53
|
if iscoroutinefunction(func):
|
|
51
54
|
return await wait_for(func(input_value), timeout=timeout)
|
|
@@ -56,6 +59,7 @@ class TimeoutStep(BaseStep):
|
|
|
56
59
|
timeout=timeout,
|
|
57
60
|
)
|
|
58
61
|
except AsyncTimeoutError:
|
|
62
|
+
self.__logger.error(f"TimeoutStep - exceeded timeout of {timeout}s")
|
|
59
63
|
raise StepTimeoutError(timeout)
|
|
60
64
|
|
|
61
65
|
return run
|
|
@@ -8,6 +8,7 @@ from typing import Any, Callable
|
|
|
8
8
|
|
|
9
9
|
from stepfunction.constants.enums import StepType
|
|
10
10
|
from stepfunction.steps.base import BaseStep
|
|
11
|
+
from stepfunction.utils.logger import setup_logger
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class WaitStep(BaseStep):
|
|
@@ -29,13 +30,16 @@ class WaitStep(BaseStep):
|
|
|
29
30
|
if duration < 0:
|
|
30
31
|
raise ValueError("duration must be a non-negative number")
|
|
31
32
|
self.duration = duration
|
|
33
|
+
self.__logger = setup_logger(__name__)
|
|
32
34
|
|
|
33
35
|
def build(self) -> Callable[[Any], Any]:
|
|
34
36
|
"""Return an async function that sleeps for ``duration`` seconds."""
|
|
35
37
|
duration = self.duration
|
|
36
38
|
|
|
37
39
|
async def wait(input_value: Any) -> Any:
|
|
40
|
+
self.__logger.debug(f"WaitStep - sleeping for {duration}s")
|
|
38
41
|
await sleep(duration)
|
|
42
|
+
self.__logger.debug(f"WaitStep - resumed after {duration}s")
|
|
39
43
|
return input_value
|
|
40
44
|
|
|
41
45
|
return wait
|
|
@@ -3,8 +3,8 @@ from typing import Any, Callable, Dict, Optional, TypedDict, Union
|
|
|
3
3
|
from stepfunction.constants.enums import StepType
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
class StepParams(TypedDict
|
|
7
|
-
func: Callable[[Any], Any]
|
|
6
|
+
class StepParams(TypedDict):
|
|
7
|
+
func: Union[Callable[[Any], Any], Dict[str, Callable[[Any], Any]]]
|
|
8
8
|
next_step: Optional[str]
|
|
9
9
|
on_failure: Optional[str]
|
|
10
10
|
branch: Optional[Union[Dict[Any, str], Callable[[Any], Optional[str]]]]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stepfunction-0.0.5 → stepfunction-0.0.7}/src/stepfunction/steps/exceptions/step_exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|