aws-durable-execution-sdk-python 1.1.0__tar.gz → 1.1.1__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.
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/PKG-INFO +1 -1
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/__about__.py +1 -1
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/execution.py +35 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/lambda_service.py +97 -3
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/state.py +6 -6
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/execution_test.py +514 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/lambda_service_test.py +618 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/CODEOWNERS +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/ISSUE_TEMPLATE/documentation.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/dependabot.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/workflows/ci.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/workflows/integration-tests.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/workflows/lintcommit.js +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/workflows/pypi-publish.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/workflows/scorecard.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/workflows/sync-package.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.github/workflows/test-parser.yml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/.gitignore +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/CODE_OF_CONDUCT.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/CONTRIBUTING.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/LICENSE +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/NOTICE +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/README.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/advanced/error-handling.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/advanced/serialization.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/advanced/testing-modes.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/api-reference/.gitkeep +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/best-practices.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/core/callbacks.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/core/child-contexts.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/core/invoke.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/core/logger.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/core/map.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/core/parallel.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/core/steps.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/core/wait.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/getting-started.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/index.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/testing-patterns/.gitkeep +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/testing-patterns/basic-tests.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/testing-patterns/complex-workflows.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/docs/testing-patterns/stores.md +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/ops/__tests__/test_parse_sdk_branch.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/ops/ci-checks.sh +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/ops/parse_sdk_branch.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/pyproject.toml +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/.gitignore +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/concurrency/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/concurrency/executor.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/concurrency/models.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/config.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/context.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/exceptions.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/identifier.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/logger.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/operation/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/operation/base.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/operation/callback.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/operation/child.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/operation/invoke.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/operation/map.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/operation/parallel.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/operation/step.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/operation/wait.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/operation/wait_for_condition.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/py.typed +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/retries.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/serdes.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/suspend.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/threading.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/types.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/src/aws_durable_execution_sdk_python/waits.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/concurrency_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/config_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/context_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/durable_executions_python_language_sdk_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/e2e/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/e2e/checkpoint_response_int_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/e2e/execution_int_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/exceptions_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/logger_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/operation/__init__.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/operation/base_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/operation/callback_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/operation/child_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/operation/invoke_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/operation/map_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/operation/parallel_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/operation/step_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/operation/wait_for_condition_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/operation/wait_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/retries_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/serdes_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/state_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/suspend_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/test_helpers.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/threading_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/types_test.py +0 -0
- {aws_durable_execution_sdk_python-1.1.0 → aws_durable_execution_sdk_python-1.1.1}/tests/waits_test.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aws-durable-execution-sdk-python
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.1
|
|
4
4
|
Summary: AWS Durable Execution SDK for Python
|
|
5
5
|
Project-URL: Documentation, https://github.com/aws/aws-durable-execution-sdk-python#readme
|
|
6
6
|
Project-URL: Issues, https://github.com/aws/aws-durable-execution-sdk-python/issues
|
|
@@ -59,6 +59,16 @@ class InitialExecutionState:
|
|
|
59
59
|
next_marker=input_dict.get("NextMarker", ""),
|
|
60
60
|
)
|
|
61
61
|
|
|
62
|
+
@staticmethod
|
|
63
|
+
def from_json_dict(input_dict: MutableMapping[str, Any]) -> InitialExecutionState:
|
|
64
|
+
operations = []
|
|
65
|
+
if input_operations := input_dict.get("Operations"):
|
|
66
|
+
operations = [Operation.from_json_dict(op) for op in input_operations]
|
|
67
|
+
return InitialExecutionState(
|
|
68
|
+
operations=operations,
|
|
69
|
+
next_marker=input_dict.get("NextMarker", ""),
|
|
70
|
+
)
|
|
71
|
+
|
|
62
72
|
def get_execution_operation(self) -> Operation | None:
|
|
63
73
|
if not self.operations:
|
|
64
74
|
# Due to payload size limitations we may have an empty operations list.
|
|
@@ -91,6 +101,12 @@ class InitialExecutionState:
|
|
|
91
101
|
"NextMarker": self.next_marker,
|
|
92
102
|
}
|
|
93
103
|
|
|
104
|
+
def to_json_dict(self) -> MutableMapping[str, Any]:
|
|
105
|
+
return {
|
|
106
|
+
"Operations": [op.to_json_dict() for op in self.operations],
|
|
107
|
+
"NextMarker": self.next_marker,
|
|
108
|
+
}
|
|
109
|
+
|
|
94
110
|
|
|
95
111
|
@dataclass(frozen=True)
|
|
96
112
|
class DurableExecutionInvocationInput:
|
|
@@ -110,6 +126,18 @@ class DurableExecutionInvocationInput:
|
|
|
110
126
|
),
|
|
111
127
|
)
|
|
112
128
|
|
|
129
|
+
@staticmethod
|
|
130
|
+
def from_json_dict(
|
|
131
|
+
input_dict: MutableMapping[str, Any],
|
|
132
|
+
) -> DurableExecutionInvocationInput:
|
|
133
|
+
return DurableExecutionInvocationInput(
|
|
134
|
+
durable_execution_arn=input_dict["DurableExecutionArn"],
|
|
135
|
+
checkpoint_token=input_dict["CheckpointToken"],
|
|
136
|
+
initial_execution_state=InitialExecutionState.from_json_dict(
|
|
137
|
+
input_dict.get("InitialExecutionState", {})
|
|
138
|
+
),
|
|
139
|
+
)
|
|
140
|
+
|
|
113
141
|
def to_dict(self) -> MutableMapping[str, Any]:
|
|
114
142
|
return {
|
|
115
143
|
"DurableExecutionArn": self.durable_execution_arn,
|
|
@@ -117,6 +145,13 @@ class DurableExecutionInvocationInput:
|
|
|
117
145
|
"InitialExecutionState": self.initial_execution_state.to_dict(),
|
|
118
146
|
}
|
|
119
147
|
|
|
148
|
+
def to_json_dict(self) -> MutableMapping[str, Any]:
|
|
149
|
+
return {
|
|
150
|
+
"DurableExecutionArn": self.durable_execution_arn,
|
|
151
|
+
"CheckpointToken": self.checkpoint_token,
|
|
152
|
+
"InitialExecutionState": self.initial_execution_state.to_json_dict(),
|
|
153
|
+
}
|
|
154
|
+
|
|
120
155
|
|
|
121
156
|
@dataclass(frozen=True)
|
|
122
157
|
class DurableExecutionInvocationInputWithClient(DurableExecutionInvocationInput):
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import copy
|
|
3
4
|
import datetime
|
|
4
5
|
import logging
|
|
5
6
|
from dataclasses import dataclass, field
|
|
@@ -692,6 +693,24 @@ class OperationUpdate:
|
|
|
692
693
|
# endregion wait
|
|
693
694
|
|
|
694
695
|
|
|
696
|
+
class TimestampConverter:
|
|
697
|
+
"""Converter for datetime/Unix timestamp conversions."""
|
|
698
|
+
|
|
699
|
+
@staticmethod
|
|
700
|
+
def to_unix_millis(dt: datetime.datetime | None) -> int | None:
|
|
701
|
+
"""Convert datetime to Unix timestamp in milliseconds."""
|
|
702
|
+
return int(dt.timestamp() * 1000) if dt else None
|
|
703
|
+
|
|
704
|
+
@staticmethod
|
|
705
|
+
def from_unix_millis(ms: int | None) -> datetime.datetime | None:
|
|
706
|
+
"""Convert Unix timestamp in milliseconds to datetime."""
|
|
707
|
+
return (
|
|
708
|
+
datetime.datetime.fromtimestamp(ms / 1000, tz=datetime.UTC)
|
|
709
|
+
if ms is not None
|
|
710
|
+
else None
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
|
|
695
714
|
@dataclass(frozen=True)
|
|
696
715
|
class Operation:
|
|
697
716
|
"""Represent the Operation type for GetDurableExecutionState and CheckpointDurableExecution."""
|
|
@@ -805,9 +824,11 @@ class Operation:
|
|
|
805
824
|
step_dict["Error"] = self.step_details.error.to_dict()
|
|
806
825
|
result["StepDetails"] = step_dict
|
|
807
826
|
if self.wait_details:
|
|
808
|
-
result["WaitDetails"] =
|
|
809
|
-
"ScheduledEndTimestamp": self.wait_details.scheduled_end_timestamp
|
|
810
|
-
|
|
827
|
+
result["WaitDetails"] = (
|
|
828
|
+
{"ScheduledEndTimestamp": self.wait_details.scheduled_end_timestamp}
|
|
829
|
+
if self.wait_details.scheduled_end_timestamp
|
|
830
|
+
else {}
|
|
831
|
+
)
|
|
811
832
|
if self.callback_details:
|
|
812
833
|
callback_dict: MutableMapping[str, Any] = {
|
|
813
834
|
"CallbackId": self.callback_details.callback_id
|
|
@@ -826,6 +847,79 @@ class Operation:
|
|
|
826
847
|
result["ChainedInvokeDetails"] = invoke_dict
|
|
827
848
|
return result
|
|
828
849
|
|
|
850
|
+
def to_json_dict(self) -> MutableMapping[str, Any]:
|
|
851
|
+
"""Convert the Operation to a JSON-serializable dictionary.
|
|
852
|
+
|
|
853
|
+
Converts datetime objects to millisecond timestamps for JSON compatibility.
|
|
854
|
+
|
|
855
|
+
Returns:
|
|
856
|
+
A dictionary with JSON-serializable values
|
|
857
|
+
"""
|
|
858
|
+
# Start with the regular to_dict output
|
|
859
|
+
result = self.to_dict()
|
|
860
|
+
|
|
861
|
+
# Convert datetime objects to millisecond timestamps
|
|
862
|
+
if ts := result.get("StartTimestamp"):
|
|
863
|
+
result["StartTimestamp"] = TimestampConverter.to_unix_millis(ts)
|
|
864
|
+
|
|
865
|
+
if ts := result.get("EndTimestamp"):
|
|
866
|
+
result["EndTimestamp"] = TimestampConverter.to_unix_millis(ts)
|
|
867
|
+
|
|
868
|
+
if (step_details := result.get("StepDetails")) and (
|
|
869
|
+
ts := step_details.get("NextAttemptTimestamp")
|
|
870
|
+
):
|
|
871
|
+
result["StepDetails"]["NextAttemptTimestamp"] = (
|
|
872
|
+
TimestampConverter.to_unix_millis(ts)
|
|
873
|
+
)
|
|
874
|
+
|
|
875
|
+
if (wait_details := result.get("WaitDetails")) and (
|
|
876
|
+
ts := wait_details.get("ScheduledEndTimestamp")
|
|
877
|
+
):
|
|
878
|
+
result["WaitDetails"]["ScheduledEndTimestamp"] = (
|
|
879
|
+
TimestampConverter.to_unix_millis(ts)
|
|
880
|
+
)
|
|
881
|
+
|
|
882
|
+
return result
|
|
883
|
+
|
|
884
|
+
@classmethod
|
|
885
|
+
def from_json_dict(cls, data: MutableMapping[str, Any]) -> Operation:
|
|
886
|
+
"""Create an Operation from a JSON-serializable dictionary.
|
|
887
|
+
|
|
888
|
+
Converts millisecond timestamps back to datetime objects.
|
|
889
|
+
|
|
890
|
+
Args:
|
|
891
|
+
data: Dictionary with JSON-serializable values (millisecond timestamps)
|
|
892
|
+
|
|
893
|
+
Returns:
|
|
894
|
+
An Operation instance with datetime objects
|
|
895
|
+
"""
|
|
896
|
+
# Make a copy to avoid modifying the original data
|
|
897
|
+
data_copy = copy.deepcopy(data)
|
|
898
|
+
|
|
899
|
+
# Convert millisecond timestamps back to datetime objects
|
|
900
|
+
if ms := data_copy.get("StartTimestamp"):
|
|
901
|
+
data_copy["StartTimestamp"] = TimestampConverter.from_unix_millis(ms)
|
|
902
|
+
|
|
903
|
+
if ms := data_copy.get("EndTimestamp"):
|
|
904
|
+
data_copy["EndTimestamp"] = TimestampConverter.from_unix_millis(ms)
|
|
905
|
+
|
|
906
|
+
if (step_details := data_copy.get("StepDetails")) and (
|
|
907
|
+
ms := step_details.get("NextAttemptTimestamp")
|
|
908
|
+
):
|
|
909
|
+
step_details["NextAttemptTimestamp"] = TimestampConverter.from_unix_millis(
|
|
910
|
+
ms
|
|
911
|
+
)
|
|
912
|
+
|
|
913
|
+
if (wait_details := data_copy.get("WaitDetails")) and (
|
|
914
|
+
ms := wait_details.get("ScheduledEndTimestamp")
|
|
915
|
+
):
|
|
916
|
+
wait_details["ScheduledEndTimestamp"] = TimestampConverter.from_unix_millis(
|
|
917
|
+
ms
|
|
918
|
+
)
|
|
919
|
+
|
|
920
|
+
# Use the existing from_dict method with the converted data
|
|
921
|
+
return cls.from_dict(data_copy)
|
|
922
|
+
|
|
829
923
|
|
|
830
924
|
@dataclass(frozen=True)
|
|
831
925
|
class CheckpointUpdatedExecutionState:
|
|
@@ -613,20 +613,20 @@ class ExecutionState:
|
|
|
613
613
|
|
|
614
614
|
logger.debug("Checkpoint batch processed successfully")
|
|
615
615
|
|
|
616
|
-
# Signal completion for any synchronous operations
|
|
617
|
-
for queued_op in batch:
|
|
618
|
-
if queued_op.completion_event is not None:
|
|
619
|
-
queued_op.completion_event.set()
|
|
620
|
-
|
|
621
616
|
# Update local token for next iteration
|
|
622
617
|
current_checkpoint_token = output.checkpoint_token
|
|
623
618
|
|
|
624
|
-
# Fetch new operations from the API
|
|
619
|
+
# Fetch new operations from the API before unblocking sync waiters
|
|
625
620
|
self.fetch_paginated_operations(
|
|
626
621
|
output.new_execution_state.operations,
|
|
627
622
|
output.checkpoint_token,
|
|
628
623
|
output.new_execution_state.next_marker,
|
|
629
624
|
)
|
|
625
|
+
|
|
626
|
+
# Signal completion for any synchronous operations
|
|
627
|
+
for queued_op in batch:
|
|
628
|
+
if queued_op.completion_event is not None:
|
|
629
|
+
queued_op.completion_event.set()
|
|
630
630
|
except Exception as e:
|
|
631
631
|
# Checkpoint failed - wake all blocked threads so they can raise error
|
|
632
632
|
# Drain both queues and signal all completion events
|