async-durable-execution-runner 2.0.0a1__py3-none-any.whl

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.
Files changed (55) hide show
  1. LICENSE +175 -0
  2. NOTICE +8 -0
  3. VERSION.py +5 -0
  4. async_durable_execution_runner/__about__.py +33 -0
  5. async_durable_execution_runner/__init__.py +23 -0
  6. async_durable_execution_runner/checkpoint/__init__.py +1 -0
  7. async_durable_execution_runner/checkpoint/processor.py +101 -0
  8. async_durable_execution_runner/checkpoint/processors/__init__.py +1 -0
  9. async_durable_execution_runner/checkpoint/processors/base.py +199 -0
  10. async_durable_execution_runner/checkpoint/processors/callback.py +89 -0
  11. async_durable_execution_runner/checkpoint/processors/context.py +59 -0
  12. async_durable_execution_runner/checkpoint/processors/execution.py +52 -0
  13. async_durable_execution_runner/checkpoint/processors/step.py +124 -0
  14. async_durable_execution_runner/checkpoint/processors/wait.py +95 -0
  15. async_durable_execution_runner/checkpoint/transformer.py +104 -0
  16. async_durable_execution_runner/checkpoint/validators/__init__.py +1 -0
  17. async_durable_execution_runner/checkpoint/validators/checkpoint.py +242 -0
  18. async_durable_execution_runner/checkpoint/validators/operations/__init__.py +1 -0
  19. async_durable_execution_runner/checkpoint/validators/operations/callback.py +45 -0
  20. async_durable_execution_runner/checkpoint/validators/operations/context.py +73 -0
  21. async_durable_execution_runner/checkpoint/validators/operations/execution.py +47 -0
  22. async_durable_execution_runner/checkpoint/validators/operations/invoke.py +56 -0
  23. async_durable_execution_runner/checkpoint/validators/operations/step.py +106 -0
  24. async_durable_execution_runner/checkpoint/validators/operations/wait.py +54 -0
  25. async_durable_execution_runner/checkpoint/validators/transitions.py +66 -0
  26. async_durable_execution_runner/cli.py +498 -0
  27. async_durable_execution_runner/client.py +50 -0
  28. async_durable_execution_runner/exceptions.py +288 -0
  29. async_durable_execution_runner/execution.py +444 -0
  30. async_durable_execution_runner/executor.py +1234 -0
  31. async_durable_execution_runner/invoker.py +340 -0
  32. async_durable_execution_runner/model.py +3296 -0
  33. async_durable_execution_runner/observer.py +144 -0
  34. async_durable_execution_runner/py.typed +1 -0
  35. async_durable_execution_runner/runner.py +1167 -0
  36. async_durable_execution_runner/scheduler.py +246 -0
  37. async_durable_execution_runner/stores/__init__.py +1 -0
  38. async_durable_execution_runner/stores/base.py +147 -0
  39. async_durable_execution_runner/stores/filesystem.py +79 -0
  40. async_durable_execution_runner/stores/memory.py +38 -0
  41. async_durable_execution_runner/stores/sqlite.py +273 -0
  42. async_durable_execution_runner/token.py +49 -0
  43. async_durable_execution_runner/web/__init__.py +1 -0
  44. async_durable_execution_runner/web/errors.py +8 -0
  45. async_durable_execution_runner/web/handlers.py +813 -0
  46. async_durable_execution_runner/web/models.py +266 -0
  47. async_durable_execution_runner/web/routes.py +692 -0
  48. async_durable_execution_runner/web/serialization.py +235 -0
  49. async_durable_execution_runner/web/server.py +243 -0
  50. async_durable_execution_runner-2.0.0a1.dist-info/METADATA +238 -0
  51. async_durable_execution_runner-2.0.0a1.dist-info/RECORD +55 -0
  52. async_durable_execution_runner-2.0.0a1.dist-info/WHEEL +4 -0
  53. async_durable_execution_runner-2.0.0a1.dist-info/entry_points.txt +2 -0
  54. async_durable_execution_runner-2.0.0a1.dist-info/licenses/LICENSE +175 -0
  55. async_durable_execution_runner-2.0.0a1.dist-info/licenses/NOTICE +1 -0
@@ -0,0 +1,45 @@
1
+ """Callback operation validator."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from async_durable_execution.lambda_service import (
6
+ Operation,
7
+ OperationAction,
8
+ OperationStatus,
9
+ OperationUpdate,
10
+ )
11
+
12
+ from async_durable_execution_runner.exceptions import (
13
+ InvalidParameterValueException,
14
+ )
15
+
16
+
17
+ VALID_ACTIONS_FOR_CALLBACK = frozenset(
18
+ [
19
+ OperationAction.START,
20
+ ]
21
+ )
22
+
23
+
24
+ class CallbackOperationValidator:
25
+ """Validates CALLBACK operation transitions."""
26
+
27
+ _ALLOWED_STATUS_TO_CANCEL = frozenset(
28
+ [
29
+ OperationStatus.STARTED,
30
+ ]
31
+ )
32
+
33
+ @staticmethod
34
+ def validate(current_state: Operation | None, update: OperationUpdate) -> None:
35
+ """Validate CALLBACK operation update."""
36
+ match update.action:
37
+ case OperationAction.START:
38
+ if current_state is not None:
39
+ msg_callback_exists: str = (
40
+ "Cannot start a CALLBACK that already exist."
41
+ )
42
+ raise InvalidParameterValueException(msg_callback_exists)
43
+ case _:
44
+ msg: str = "Invalid action for CALLBACK operation."
45
+ raise InvalidParameterValueException(msg)
@@ -0,0 +1,73 @@
1
+ """Context operation validator."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from async_durable_execution.lambda_service import (
6
+ Operation,
7
+ OperationAction,
8
+ OperationStatus,
9
+ OperationUpdate,
10
+ )
11
+
12
+ from async_durable_execution_runner.exceptions import (
13
+ InvalidParameterValueException,
14
+ )
15
+
16
+
17
+ VALID_ACTIONS_FOR_CONTEXT = frozenset(
18
+ [
19
+ OperationAction.START,
20
+ OperationAction.FAIL,
21
+ OperationAction.SUCCEED,
22
+ ]
23
+ )
24
+
25
+
26
+ class ContextOperationValidator:
27
+ """Validates CONTEXT operation transitions."""
28
+
29
+ _ALLOWED_STATUS_TO_CLOSE = frozenset(
30
+ [
31
+ OperationStatus.STARTED,
32
+ ]
33
+ )
34
+
35
+ @staticmethod
36
+ def validate(current_state: Operation | None, update: OperationUpdate) -> None:
37
+ """Validate CONTEXT operation update."""
38
+ match update.action:
39
+ case OperationAction.START:
40
+ if current_state is not None:
41
+ msg_context_exists: str = (
42
+ "Cannot start a CONTEXT that already exist."
43
+ )
44
+
45
+ raise InvalidParameterValueException(msg_context_exists)
46
+ case OperationAction.FAIL | OperationAction.SUCCEED:
47
+ if (
48
+ current_state is not None
49
+ and current_state.status
50
+ not in ContextOperationValidator._ALLOWED_STATUS_TO_CLOSE
51
+ ):
52
+ msg_context_close: str = "Invalid current CONTEXT state to close."
53
+
54
+ raise InvalidParameterValueException(msg_context_close)
55
+ if update.action == OperationAction.FAIL and update.payload is not None:
56
+ msg_context_fail_payload: str = (
57
+ "Cannot provide a Payload for FAIL action."
58
+ )
59
+
60
+ raise InvalidParameterValueException(msg_context_fail_payload)
61
+ if (
62
+ update.action == OperationAction.SUCCEED
63
+ and update.error is not None
64
+ ):
65
+ msg_context_succeed_error: str = (
66
+ "Cannot provide an Error for SUCCEED action."
67
+ )
68
+
69
+ raise InvalidParameterValueException(msg_context_succeed_error)
70
+ case _:
71
+ msg_context_invalid: str = "Invalid CONTEXT action."
72
+
73
+ raise InvalidParameterValueException(msg_context_invalid)
@@ -0,0 +1,47 @@
1
+ """Execution operation validator."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from async_durable_execution.lambda_service import (
6
+ OperationAction,
7
+ OperationUpdate,
8
+ )
9
+
10
+ from async_durable_execution_runner.exceptions import (
11
+ InvalidParameterValueException,
12
+ )
13
+
14
+
15
+ VALID_ACTIONS_FOR_EXECUTION = frozenset(
16
+ [
17
+ OperationAction.SUCCEED,
18
+ OperationAction.FAIL,
19
+ ]
20
+ )
21
+
22
+
23
+ class ExecutionOperationValidator:
24
+ """Validates EXECUTION operation transitions."""
25
+
26
+ @staticmethod
27
+ def validate(update: OperationUpdate) -> None:
28
+ """Validate EXECUTION operation update."""
29
+ match update.action:
30
+ case OperationAction.SUCCEED:
31
+ if update.error is not None:
32
+ msg_exec_succeed_error: str = (
33
+ "Cannot provide an Error for SUCCEED action."
34
+ )
35
+
36
+ raise InvalidParameterValueException(msg_exec_succeed_error)
37
+ case OperationAction.FAIL:
38
+ if update.payload is not None:
39
+ msg_exec_fail_payload: str = (
40
+ "Cannot provide a Payload for FAIL action."
41
+ )
42
+
43
+ raise InvalidParameterValueException(msg_exec_fail_payload)
44
+ case _:
45
+ msg_exec_invalid: str = "Invalid EXECUTION action."
46
+
47
+ raise InvalidParameterValueException(msg_exec_invalid)
@@ -0,0 +1,56 @@
1
+ """Invoke operation validator."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from async_durable_execution.lambda_service import (
6
+ Operation,
7
+ OperationAction,
8
+ OperationStatus,
9
+ OperationUpdate,
10
+ )
11
+
12
+ from async_durable_execution_runner.exceptions import (
13
+ InvalidParameterValueException,
14
+ )
15
+
16
+
17
+ VALID_ACTIONS_FOR_INVOKE = frozenset(
18
+ [
19
+ OperationAction.START,
20
+ OperationAction.CANCEL,
21
+ ]
22
+ )
23
+
24
+
25
+ class ChainedInvokeOperationValidator:
26
+ """Validates INVOKE operation transitions."""
27
+
28
+ _ALLOWED_STATUS_TO_CANCEL = frozenset(
29
+ [
30
+ OperationStatus.STARTED,
31
+ ]
32
+ )
33
+
34
+ @staticmethod
35
+ def validate(current_state: Operation | None, update: OperationUpdate) -> None:
36
+ """Validate INVOKE operation update."""
37
+ match update.action:
38
+ case OperationAction.START:
39
+ if current_state is not None:
40
+ msg_invoke_exists: str = (
41
+ "Cannot start an INVOKE that already exist."
42
+ )
43
+
44
+ raise InvalidParameterValueException(msg_invoke_exists)
45
+ case OperationAction.CANCEL:
46
+ if (
47
+ current_state is None
48
+ or current_state.status
49
+ not in ChainedInvokeOperationValidator._ALLOWED_STATUS_TO_CANCEL
50
+ ):
51
+ msg_invoke_cancel: str = "Cannot cancel an INVOKE that does not exist or has already completed."
52
+ raise InvalidParameterValueException(msg_invoke_cancel)
53
+ case _:
54
+ msg_invoke_invalid: str = "Invalid INVOKE action."
55
+
56
+ raise InvalidParameterValueException(msg_invoke_invalid)
@@ -0,0 +1,106 @@
1
+ """Step operation validator."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from async_durable_execution.lambda_service import (
6
+ Operation,
7
+ OperationAction,
8
+ OperationStatus,
9
+ OperationUpdate,
10
+ )
11
+
12
+ from async_durable_execution_runner.exceptions import (
13
+ InvalidParameterValueException,
14
+ )
15
+
16
+
17
+ VALID_ACTIONS_FOR_STEP = frozenset(
18
+ [
19
+ OperationAction.START,
20
+ OperationAction.FAIL,
21
+ OperationAction.RETRY,
22
+ OperationAction.SUCCEED,
23
+ ]
24
+ )
25
+
26
+
27
+ class StepOperationValidator:
28
+ """Validates STEP operation transitions."""
29
+
30
+ _ALLOWED_STATUS_TO_CLOSE = frozenset(
31
+ [
32
+ OperationStatus.STARTED,
33
+ OperationStatus.READY,
34
+ ]
35
+ )
36
+
37
+ _ALLOWED_STATUS_TO_START = frozenset(
38
+ [
39
+ OperationStatus.READY,
40
+ ]
41
+ )
42
+
43
+ _ALLOWED_STATUS_TO_REATTEMPT = frozenset(
44
+ [
45
+ OperationStatus.STARTED,
46
+ OperationStatus.READY,
47
+ ]
48
+ )
49
+
50
+ @staticmethod
51
+ def validate(current_state: Operation | None, update: OperationUpdate) -> None:
52
+ """Validate STEP operation update."""
53
+ if current_state is None:
54
+ return
55
+
56
+ match update.action:
57
+ case OperationAction.START:
58
+ if (
59
+ current_state.status
60
+ not in StepOperationValidator._ALLOWED_STATUS_TO_START
61
+ ):
62
+ msg_step_start: str = "Invalid current STEP state to start."
63
+
64
+ raise InvalidParameterValueException(msg_step_start)
65
+ case OperationAction.FAIL | OperationAction.SUCCEED:
66
+ if (
67
+ current_state.status
68
+ not in StepOperationValidator._ALLOWED_STATUS_TO_CLOSE
69
+ ):
70
+ msg_step_close: str = "Invalid current STEP state to close."
71
+
72
+ raise InvalidParameterValueException(msg_step_close)
73
+ if update.action == OperationAction.FAIL and update.payload is not None:
74
+ msg_fail_payload: str = "Cannot provide a Payload for FAIL action."
75
+
76
+ raise InvalidParameterValueException(msg_fail_payload)
77
+ if (
78
+ update.action == OperationAction.SUCCEED
79
+ and update.error is not None
80
+ ):
81
+ msg_succeed_error: str = (
82
+ "Cannot provide an Error for SUCCEED action."
83
+ )
84
+
85
+ raise InvalidParameterValueException(msg_succeed_error)
86
+ case OperationAction.RETRY:
87
+ if (
88
+ current_state.status
89
+ not in StepOperationValidator._ALLOWED_STATUS_TO_REATTEMPT
90
+ ):
91
+ msg_step_retry: str = "Invalid current STEP state to re-attempt."
92
+
93
+ raise InvalidParameterValueException(msg_step_retry)
94
+ if update.step_options is None:
95
+ msg_step_options: str = "Invalid StepOptions for the given action."
96
+
97
+ raise InvalidParameterValueException(msg_step_options)
98
+ if update.error is not None and update.payload is not None:
99
+ msg_retry_both: str = (
100
+ "Cannot provide both error and payload to RETRY a STEP."
101
+ )
102
+ raise InvalidParameterValueException(msg_retry_both)
103
+ case _:
104
+ msg_step_invalid: str = "Invalid STEP action."
105
+
106
+ raise InvalidParameterValueException(msg_step_invalid)
@@ -0,0 +1,54 @@
1
+ """Wait operation validator."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from async_durable_execution.lambda_service import (
6
+ Operation,
7
+ OperationAction,
8
+ OperationStatus,
9
+ OperationUpdate,
10
+ )
11
+
12
+ from async_durable_execution_runner.exceptions import (
13
+ InvalidParameterValueException,
14
+ )
15
+
16
+
17
+ VALID_ACTIONS_FOR_WAIT = frozenset(
18
+ [
19
+ OperationAction.START,
20
+ OperationAction.CANCEL,
21
+ ]
22
+ )
23
+
24
+
25
+ class WaitOperationValidator:
26
+ """Validates WAIT operation transitions."""
27
+
28
+ _ALLOWED_STATUS_TO_CANCEL = frozenset(
29
+ [
30
+ OperationStatus.STARTED,
31
+ ]
32
+ )
33
+
34
+ @staticmethod
35
+ def validate(current_state: Operation | None, update: OperationUpdate) -> None:
36
+ """Validate WAIT operation update."""
37
+ match update.action:
38
+ case OperationAction.START:
39
+ if current_state is not None:
40
+ msg_wait_exists: str = "Cannot start a WAIT that already exist."
41
+
42
+ raise InvalidParameterValueException(msg_wait_exists)
43
+ case OperationAction.CANCEL:
44
+ if (
45
+ current_state is None
46
+ or current_state.status
47
+ not in WaitOperationValidator._ALLOWED_STATUS_TO_CANCEL
48
+ ):
49
+ msg_wait_cancel: str = "Cannot cancel a WAIT that does not exist or has already completed."
50
+ raise InvalidParameterValueException(msg_wait_cancel)
51
+ case _:
52
+ msg_wait_invalid: str = "Invalid WAIT action."
53
+
54
+ raise InvalidParameterValueException(msg_wait_invalid)
@@ -0,0 +1,66 @@
1
+ """Validator for valid actions by operation type."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import ClassVar
6
+
7
+ from async_durable_execution.lambda_service import (
8
+ OperationAction,
9
+ OperationType,
10
+ )
11
+
12
+ from async_durable_execution_runner.checkpoint.validators.operations.callback import (
13
+ VALID_ACTIONS_FOR_CALLBACK,
14
+ )
15
+ from async_durable_execution_runner.checkpoint.validators.operations.context import (
16
+ VALID_ACTIONS_FOR_CONTEXT,
17
+ )
18
+ from async_durable_execution_runner.checkpoint.validators.operations.execution import (
19
+ VALID_ACTIONS_FOR_EXECUTION,
20
+ )
21
+ from async_durable_execution_runner.checkpoint.validators.operations.invoke import (
22
+ VALID_ACTIONS_FOR_INVOKE,
23
+ )
24
+ from async_durable_execution_runner.checkpoint.validators.operations.step import (
25
+ VALID_ACTIONS_FOR_STEP,
26
+ )
27
+ from async_durable_execution_runner.checkpoint.validators.operations.wait import (
28
+ VALID_ACTIONS_FOR_WAIT,
29
+ )
30
+ from async_durable_execution_runner.exceptions import (
31
+ InvalidParameterValueException,
32
+ )
33
+
34
+
35
+ class ValidActionsByOperationTypeValidator:
36
+ """Validates that the given action is valid for the given operation type."""
37
+
38
+ _VALID_ACTIONS_BY_OPERATION_TYPE: ClassVar[
39
+ dict[OperationType, frozenset[OperationAction]]
40
+ ] = {
41
+ OperationType.STEP: VALID_ACTIONS_FOR_STEP,
42
+ OperationType.CONTEXT: VALID_ACTIONS_FOR_CONTEXT,
43
+ OperationType.WAIT: VALID_ACTIONS_FOR_WAIT,
44
+ OperationType.CALLBACK: VALID_ACTIONS_FOR_CALLBACK,
45
+ OperationType.CHAINED_INVOKE: VALID_ACTIONS_FOR_INVOKE,
46
+ OperationType.EXECUTION: VALID_ACTIONS_FOR_EXECUTION,
47
+ }
48
+
49
+ @staticmethod
50
+ def validate(operation_type: OperationType, action: OperationAction) -> None:
51
+ """Validate that the action is valid for the operation type."""
52
+ valid_actions = (
53
+ ValidActionsByOperationTypeValidator._VALID_ACTIONS_BY_OPERATION_TYPE.get(
54
+ operation_type
55
+ )
56
+ )
57
+
58
+ if valid_actions is None:
59
+ msg_unknown_op: str = "Unknown operation type."
60
+
61
+ raise InvalidParameterValueException(msg_unknown_op)
62
+
63
+ if action not in valid_actions:
64
+ msg_invalid_action: str = "Invalid action for the given operation type."
65
+
66
+ raise InvalidParameterValueException(msg_invalid_action)