durable-workflow 2.3.3__tar.gz → 2.3.4__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.
- {durable_workflow-2.3.3/src/durable_workflow.egg-info → durable_workflow-2.3.4}/PKG-INFO +1 -1
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/pyproject.toml +3 -3
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/retry_policy.py +30 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4/src/durable_workflow.egg-info}/PKG-INFO +1 -1
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_storage_admission.py +63 -4
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/LICENSE +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/README.md +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/setup.cfg +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/__init__.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/_avro.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/activity.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/auth_composition.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/client.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/errors.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/external_storage.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/external_task_input.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/external_task_result.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/history_bundle_verify.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/interceptors.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/invocable.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/metrics.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/nexus.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/py.typed +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/python_conformance.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/replay_conformance.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/replay_verify.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/serializer.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/sync.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/testing.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/worker.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/worker_session.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/workflow.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/workflow_updates_conformance.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow.egg-info/SOURCES.txt +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow.egg-info/dependency_links.txt +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow.egg-info/entry_points.txt +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow.egg-info/requires.txt +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow.egg-info/top_level.txt +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_activity_context.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_auth_composition.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_avro_value_benchmark.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_avro_value_protocol.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_ci_checkout.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_ci_integration_endpoint.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_client.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_codec_regression_corpus.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_control_plane_parity_fixtures.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_docstring_cross_references.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_durable_selection.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_errors.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_external_storage.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_external_task_input.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_external_task_result.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_golden_history_replay.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_history_bundle_verify.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_history_event_contract.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_invocable.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_message_streams.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_metrics.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_order_processing_example.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_parallel_completion_order_replay.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_parallel_saga_authoring.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_public_boundary_scanner.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_pypi_project_surface.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_python_conformance.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_queries.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_readme_quickstart.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_redrive_replay.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_release_metadata.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_replay.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_replay_conformance.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_replay_regression_corpus.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_replay_verify.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_retry_policy.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_runtime_external_payload_transport.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_schedules.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_serializer.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_signals.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_sleep.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_standalone_activity_client.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_sync.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_testing_harness.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_update_signal_condition_replay.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_updates.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_wait_condition.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_worker.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_worker_session.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_workflow_result_timeout.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_workflow_streams.py +0 -0
- {durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_workflow_updates_conformance.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "durable-workflow"
|
|
7
|
-
version = "2.3.
|
|
7
|
+
version = "2.3.4"
|
|
8
8
|
description = "Python client and worker SDK for Durable Workflow Cloud and self-hosted Server"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -71,8 +71,8 @@ durable-workflow-replay-conformance = "durable_workflow.replay_conformance:main"
|
|
|
71
71
|
durable-workflow-workflow-updates-conformance = "durable_workflow.workflow_updates_conformance:main"
|
|
72
72
|
|
|
73
73
|
[tool.durable-workflow]
|
|
74
|
-
product-train = "2.3.
|
|
75
|
-
registry-version = "2.3.
|
|
74
|
+
product-train = "2.3.4"
|
|
75
|
+
registry-version = "2.3.4"
|
|
76
76
|
supported-server-versions = "2.4.8"
|
|
77
77
|
worker-protocol-version = "1.19"
|
|
78
78
|
control-plane-version = "2"
|
|
@@ -80,6 +80,18 @@ def _backend_unavailable_refusal(exc: Exception) -> tuple[bool, int | None]:
|
|
|
80
80
|
"/api/worker/heartbeat": "heartbeat_worker",
|
|
81
81
|
}
|
|
82
82
|
operation = next((name for path, name in operations.items() if request.url.path.endswith(path)), None)
|
|
83
|
+
_, task_heartbeat_marker, task_heartbeat_tail = request.url.path.rpartition(
|
|
84
|
+
"/api/worker/workflow-tasks/"
|
|
85
|
+
)
|
|
86
|
+
task_id = task_heartbeat_tail.removesuffix("/heartbeat")
|
|
87
|
+
task_heartbeat = (
|
|
88
|
+
bool(task_heartbeat_marker)
|
|
89
|
+
and task_heartbeat_tail.endswith("/heartbeat")
|
|
90
|
+
and bool(task_id)
|
|
91
|
+
and "/" not in task_id
|
|
92
|
+
)
|
|
93
|
+
if task_heartbeat:
|
|
94
|
+
operation = "heartbeat_workflow_task"
|
|
83
95
|
if operation is None:
|
|
84
96
|
return False, None
|
|
85
97
|
try:
|
|
@@ -97,6 +109,24 @@ def _backend_unavailable_refusal(exc: Exception) -> tuple[bool, int | None]:
|
|
|
97
109
|
worker_id = submitted.get("worker_id")
|
|
98
110
|
queue = submitted.get("task_queue")
|
|
99
111
|
delay = body.get("retry_after_seconds")
|
|
112
|
+
if task_heartbeat:
|
|
113
|
+
lease_owner = submitted.get("lease_owner")
|
|
114
|
+
attempt = submitted.get("workflow_task_attempt")
|
|
115
|
+
if (
|
|
116
|
+
not isinstance(lease_owner, str) or not lease_owner
|
|
117
|
+
or type(attempt) is not int or attempt <= 0
|
|
118
|
+
or body.get("operation") != operation
|
|
119
|
+
or body.get("outcome") != "unknown"
|
|
120
|
+
or body.get("worker_id") != lease_owner
|
|
121
|
+
or body.get("task_queue") is not None
|
|
122
|
+
or body.get("task_id") != task_id
|
|
123
|
+
or body.get("lease_owner") != lease_owner
|
|
124
|
+
or body.get("workflow_task_attempt") != attempt
|
|
125
|
+
or body.get("retryable") is not True
|
|
126
|
+
or type(delay) is not int or delay <= 0
|
|
127
|
+
):
|
|
128
|
+
return True, None
|
|
129
|
+
return True, delay
|
|
100
130
|
if (
|
|
101
131
|
not isinstance(worker_id, str) or not worker_id
|
|
102
132
|
or body.get("operation") != operation
|
|
@@ -42,7 +42,8 @@ def pressure(poll_id: str | None = None, *, reason: str = "storage_pressure", en
|
|
|
42
42
|
def backend_unavailable(request: httpx.Request) -> dict[str, Any]:
|
|
43
43
|
submitted = json.loads(request.content)
|
|
44
44
|
path = request.url.path
|
|
45
|
-
|
|
45
|
+
task_heartbeat = "/api/worker/workflow-tasks/" in path and path.endswith("/heartbeat")
|
|
46
|
+
operation = "heartbeat_workflow_task" if task_heartbeat else {
|
|
46
47
|
"/api/worker/workflow-tasks/poll": "poll_workflow_task",
|
|
47
48
|
"/api/worker/activity-tasks/poll": "poll_activity_task",
|
|
48
49
|
"/api/worker/query-tasks/poll": "poll_query_task",
|
|
@@ -51,9 +52,16 @@ def backend_unavailable(request: httpx.Request) -> dict[str, Any]:
|
|
|
51
52
|
}[path]
|
|
52
53
|
body: dict[str, Any] = {
|
|
53
54
|
"reason": "backend_unavailable", "operation": operation, "outcome": "unknown",
|
|
54
|
-
"worker_id": submitted
|
|
55
|
+
"worker_id": submitted.get("lease_owner") if task_heartbeat else submitted["worker_id"],
|
|
56
|
+
"task_queue": submitted.get("task_queue"),
|
|
55
57
|
"retryable": True, "retry_after_seconds": 1,
|
|
56
58
|
}
|
|
59
|
+
if task_heartbeat:
|
|
60
|
+
body.update({
|
|
61
|
+
"task_id": path.rpartition("/api/worker/workflow-tasks/")[2].removesuffix("/heartbeat"),
|
|
62
|
+
"lease_owner": submitted["lease_owner"],
|
|
63
|
+
"workflow_task_attempt": submitted["workflow_task_attempt"],
|
|
64
|
+
})
|
|
57
65
|
if path.endswith("/poll"):
|
|
58
66
|
body.update({
|
|
59
67
|
"task": None, "poll_status": "backend_unavailable",
|
|
@@ -85,9 +93,9 @@ def retry_sleeps(monkeypatch: pytest.MonkeyPatch) -> list[float]:
|
|
|
85
93
|
return sleeps
|
|
86
94
|
|
|
87
95
|
|
|
88
|
-
def client_for(handler: Callable[..., Any]) -> Client:
|
|
96
|
+
def client_for(handler: Callable[..., Any], base_url: str = "https://runtime.example") -> Client:
|
|
89
97
|
client = Client(
|
|
90
|
-
|
|
98
|
+
base_url, token="test-runtime-token",
|
|
91
99
|
retry_policy=TransportRetryPolicy(max_attempts=2, initial_backoff_seconds=0, jitter=False),
|
|
92
100
|
)
|
|
93
101
|
client._http = httpx.AsyncClient(base_url=client.base_url, transport=httpx.MockTransport(handler))
|
|
@@ -186,6 +194,57 @@ async def test_backend_outage_retries_worker_registration_and_heartbeat(
|
|
|
186
194
|
assert sum(retry_sleeps) == pytest.approx(4)
|
|
187
195
|
|
|
188
196
|
|
|
197
|
+
@pytest.mark.parametrize("base_url", ["https://runtime.example", "https://runtime.example/managed/namespace"])
|
|
198
|
+
async def test_backend_outage_retries_workflow_task_heartbeat_with_same_fence(
|
|
199
|
+
base_url: str, retry_sleeps: list[float],
|
|
200
|
+
) -> None:
|
|
201
|
+
requests: list[bytes] = []
|
|
202
|
+
|
|
203
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
204
|
+
requests.append(request.content)
|
|
205
|
+
if len(requests) <= 4:
|
|
206
|
+
return httpx.Response(503, json=backend_unavailable(request))
|
|
207
|
+
return httpx.Response(200, json={
|
|
208
|
+
"task_id": "task-1", "lease_owner": "worker-1",
|
|
209
|
+
"workflow_task_attempt": 3, "renewed": True,
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
async with client_for(handler, base_url) as client:
|
|
213
|
+
with worker_scope():
|
|
214
|
+
result = await client.heartbeat_workflow_task(
|
|
215
|
+
task_id="task-1", lease_owner="worker-1", workflow_task_attempt=3,
|
|
216
|
+
)
|
|
217
|
+
assert result["renewed"] is True
|
|
218
|
+
assert len(requests) == 5
|
|
219
|
+
assert len(set(requests)) == 1
|
|
220
|
+
assert sum(retry_sleeps) == pytest.approx(4)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
@pytest.mark.parametrize("override", [
|
|
224
|
+
{"task_id": "other-task"}, {"lease_owner": "other-worker"},
|
|
225
|
+
{"worker_id": "other-worker"}, {"workflow_task_attempt": 4},
|
|
226
|
+
{"operation": "heartbeat_worker"}, {"outcome": "failed"},
|
|
227
|
+
{"retryable": False}, {"retry_after_seconds": 0},
|
|
228
|
+
])
|
|
229
|
+
async def test_invalid_workflow_task_heartbeat_backend_response_is_not_retried(
|
|
230
|
+
override: dict[str, Any], retry_sleeps: list[float],
|
|
231
|
+
) -> None:
|
|
232
|
+
calls = 0
|
|
233
|
+
|
|
234
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
235
|
+
nonlocal calls
|
|
236
|
+
calls += 1
|
|
237
|
+
return httpx.Response(503, json={**backend_unavailable(request), **override})
|
|
238
|
+
|
|
239
|
+
async with client_for(handler) as client:
|
|
240
|
+
with worker_scope(), pytest.raises(ServerError):
|
|
241
|
+
await client.heartbeat_workflow_task(
|
|
242
|
+
task_id="task-1", lease_owner="worker-1", workflow_task_attempt=3,
|
|
243
|
+
)
|
|
244
|
+
assert calls == 1
|
|
245
|
+
assert not retry_sleeps
|
|
246
|
+
|
|
247
|
+
|
|
189
248
|
@pytest.mark.parametrize("override", [
|
|
190
249
|
{"operation": "poll_activity_task"},
|
|
191
250
|
{"outcome": "failed"}, {"worker_id": "other-worker"},
|
|
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
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/external_task_input.py
RENAMED
|
File without changes
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/external_task_result.py
RENAMED
|
File without changes
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/history_bundle_verify.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/python_conformance.py
RENAMED
|
File without changes
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow/replay_conformance.py
RENAMED
|
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
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow.egg-info/requires.txt
RENAMED
|
File without changes
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/src/durable_workflow.egg-info/top_level.txt
RENAMED
|
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
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_control_plane_parity_fixtures.py
RENAMED
|
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
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_parallel_completion_order_replay.py
RENAMED
|
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
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_runtime_external_payload_transport.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_update_signal_condition_replay.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.3.3 → durable_workflow-2.3.4}/tests/test_workflow_updates_conformance.py
RENAMED
|
File without changes
|