durable-workflow 2.3.4__tar.gz → 2.3.6__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.4/src/durable_workflow.egg-info → durable_workflow-2.3.6}/PKG-INFO +1 -1
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/pyproject.toml +3 -3
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/client.py +70 -34
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/external_storage.py +1 -1
- {durable_workflow-2.3.4 → durable_workflow-2.3.6/src/durable_workflow.egg-info}/PKG-INFO +1 -1
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_client.py +47 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_external_storage.py +21 -1
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_workflow_result_timeout.py +3 -1
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/LICENSE +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/README.md +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/setup.cfg +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/__init__.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/_avro.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/activity.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/auth_composition.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/errors.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/external_task_input.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/external_task_result.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/history_bundle_verify.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/interceptors.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/invocable.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/metrics.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/nexus.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/py.typed +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/python_conformance.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/replay_conformance.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/replay_verify.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/retry_policy.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/serializer.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/sync.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/testing.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/worker.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/worker_session.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/workflow.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/workflow_updates_conformance.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow.egg-info/SOURCES.txt +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow.egg-info/dependency_links.txt +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow.egg-info/entry_points.txt +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow.egg-info/requires.txt +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow.egg-info/top_level.txt +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_activity_context.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_auth_composition.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_avro_value_benchmark.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_avro_value_protocol.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_ci_checkout.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_ci_integration_endpoint.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_codec_regression_corpus.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_control_plane_parity_fixtures.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_docstring_cross_references.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_durable_selection.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_errors.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_external_task_input.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_external_task_result.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_golden_history_replay.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_history_bundle_verify.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_history_event_contract.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_invocable.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_message_streams.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_metrics.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_order_processing_example.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_parallel_completion_order_replay.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_parallel_saga_authoring.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_public_boundary_scanner.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_pypi_project_surface.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_python_conformance.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_queries.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_readme_quickstart.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_redrive_replay.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_release_metadata.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_replay.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_replay_conformance.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_replay_regression_corpus.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_replay_verify.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_retry_policy.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_runtime_external_payload_transport.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_schedules.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_serializer.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_signals.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_sleep.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_standalone_activity_client.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_storage_admission.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_sync.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_testing_harness.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_update_signal_condition_replay.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_updates.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_wait_condition.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_worker.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_worker_session.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_workflow_streams.py +0 -0
- {durable_workflow-2.3.4 → durable_workflow-2.3.6}/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.6"
|
|
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.6"
|
|
75
|
+
registry-version = "2.3.6"
|
|
76
76
|
supported-server-versions = "2.4.8"
|
|
77
77
|
worker-protocol-version = "1.19"
|
|
78
78
|
control-plane-version = "2"
|
|
@@ -1271,11 +1271,21 @@ class WorkflowHandle:
|
|
|
1271
1271
|
"""Return the server's current view of this workflow. See :meth:`Client.describe_workflow`."""
|
|
1272
1272
|
return await self._client.describe_workflow(self.workflow_id)
|
|
1273
1273
|
|
|
1274
|
-
async def get_history(
|
|
1275
|
-
|
|
1274
|
+
async def get_history(
|
|
1275
|
+
self,
|
|
1276
|
+
*,
|
|
1277
|
+
page_size: int | None = None,
|
|
1278
|
+
next_page_token: str | None = None,
|
|
1279
|
+
) -> Any:
|
|
1280
|
+
"""Fetch one page of this run's history. See :meth:`Client.get_history`."""
|
|
1276
1281
|
if self.run_id is None:
|
|
1277
1282
|
raise ValueError("run_id is required to fetch workflow history from a handle")
|
|
1278
|
-
|
|
1283
|
+
options: dict[str, Any] = {}
|
|
1284
|
+
if page_size is not None:
|
|
1285
|
+
options["page_size"] = page_size
|
|
1286
|
+
if next_page_token is not None:
|
|
1287
|
+
options["next_page_token"] = next_page_token
|
|
1288
|
+
return await self._client.get_history(self.workflow_id, self.run_id, **options)
|
|
1279
1289
|
|
|
1280
1290
|
async def export_history(self) -> Any:
|
|
1281
1291
|
"""Export this run's history as a replay bundle. See :meth:`Client.export_history`."""
|
|
@@ -3462,10 +3472,26 @@ class Client:
|
|
|
3462
3472
|
next_page_token=data.get("next_page_token"),
|
|
3463
3473
|
)
|
|
3464
3474
|
|
|
3465
|
-
async def get_history(
|
|
3466
|
-
|
|
3475
|
+
async def get_history(
|
|
3476
|
+
self,
|
|
3477
|
+
workflow_id: str,
|
|
3478
|
+
run_id: str,
|
|
3479
|
+
*,
|
|
3480
|
+
page_size: int | None = None,
|
|
3481
|
+
next_page_token: str | None = None,
|
|
3482
|
+
) -> Any:
|
|
3483
|
+
"""Fetch one history page; pass its opaque next_page_token for the next page."""
|
|
3484
|
+
params: dict[str, str] = {}
|
|
3485
|
+
if page_size is not None:
|
|
3486
|
+
params["page_size"] = str(page_size)
|
|
3487
|
+
if next_page_token is not None:
|
|
3488
|
+
params["next_page_token"] = next_page_token
|
|
3489
|
+
query = urlencode(params)
|
|
3490
|
+
path = f"/workflows/{workflow_id}/runs/{run_id}/history"
|
|
3491
|
+
if query:
|
|
3492
|
+
path += f"?{query}"
|
|
3467
3493
|
return await self._request(
|
|
3468
|
-
"GET",
|
|
3494
|
+
"GET", path, context=workflow_id
|
|
3469
3495
|
)
|
|
3470
3496
|
|
|
3471
3497
|
async def export_history(self, workflow_id: str, run_id: str) -> Any:
|
|
@@ -4240,34 +4266,44 @@ class Client:
|
|
|
4240
4266
|
run_id = handle.run_id or desc.run_id
|
|
4241
4267
|
if run_id is None:
|
|
4242
4268
|
raise WorkflowFailed("no run_id available to fetch history")
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4269
|
+
page_token: str | None = None
|
|
4270
|
+
seen_tokens: set[str] = set()
|
|
4271
|
+
while True:
|
|
4272
|
+
history = await self.get_history(
|
|
4273
|
+
handle.workflow_id, run_id, page_size=1000, next_page_token=page_token
|
|
4274
|
+
)
|
|
4275
|
+
events = history.get("events", [])
|
|
4276
|
+
for ev in reversed(events):
|
|
4277
|
+
etype = ev.get("event_type")
|
|
4278
|
+
payload = ev.get("payload") or {}
|
|
4279
|
+
if etype == "WorkflowCompleted":
|
|
4280
|
+
return serializer.decode_envelope(
|
|
4281
|
+
payload.get("output"),
|
|
4282
|
+
codec=payload.get("payload_codec") or desc.payload_codec,
|
|
4283
|
+
external_storage=self.external_storage,
|
|
4284
|
+
external_storage_cache=self.external_storage_cache,
|
|
4285
|
+
)
|
|
4286
|
+
if etype == "WorkflowFailed":
|
|
4287
|
+
raise WorkflowFailed(
|
|
4288
|
+
payload.get("message", "workflow failed"),
|
|
4289
|
+
payload.get("exception_class"),
|
|
4290
|
+
)
|
|
4291
|
+
if etype == "WorkflowTerminated":
|
|
4292
|
+
raise WorkflowTerminated(
|
|
4293
|
+
payload.get("reason", "workflow was terminated")
|
|
4294
|
+
)
|
|
4295
|
+
if etype == "WorkflowCancelled":
|
|
4296
|
+
raise WorkflowCancelled(
|
|
4297
|
+
payload.get("reason", "workflow was cancelled")
|
|
4298
|
+
)
|
|
4299
|
+
if etype == "WorkflowTimedOut":
|
|
4300
|
+
raise WorkflowTimedOut()
|
|
4301
|
+
page_token = history.get("next_page_token")
|
|
4302
|
+
if not page_token:
|
|
4303
|
+
return None
|
|
4304
|
+
if page_token in seen_tokens:
|
|
4305
|
+
raise RuntimeError("history pagination repeated a page token")
|
|
4306
|
+
seen_tokens.add(page_token)
|
|
4271
4307
|
if asyncio.get_running_loop().time() > deadline:
|
|
4272
4308
|
raise TimeoutError(
|
|
4273
4309
|
f"workflow {handle.workflow_id} not terminal after {timeout}s (status={status})"
|
|
@@ -250,7 +250,7 @@ class ExternalPayloadCache:
|
|
|
250
250
|
contract as a fresh driver fetch.
|
|
251
251
|
"""
|
|
252
252
|
|
|
253
|
-
def __init__(self, *, max_entries: int =
|
|
253
|
+
def __init__(self, *, max_entries: int = 1024, max_bytes: int = 16 * 1024 * 1024) -> None:
|
|
254
254
|
if max_entries < 1:
|
|
255
255
|
raise ValueError("external payload cache max_entries must be at least 1")
|
|
256
256
|
if max_bytes < 1:
|
|
@@ -791,6 +791,17 @@ class TestWorkflowRunVisibility:
|
|
|
791
791
|
|
|
792
792
|
|
|
793
793
|
class TestWorkflowHandleControlPlane:
|
|
794
|
+
@pytest.mark.asyncio
|
|
795
|
+
async def test_history_page_token_is_encoded(self, client: Client) -> None:
|
|
796
|
+
response = _mock_response(200, {"events": [], "next_page_token": None})
|
|
797
|
+
with patch.object(client._http, "request", new_callable=AsyncMock, return_value=response) as request:
|
|
798
|
+
page = await client.get_history("wf-1", "run-1", page_size=1000, next_page_token="opaque+/=")
|
|
799
|
+
|
|
800
|
+
assert page["events"] == []
|
|
801
|
+
assert request.call_args.args[1] == (
|
|
802
|
+
"/api/workflows/wf-1/runs/run-1/history?page_size=1000&next_page_token=opaque%2B%2F%3D"
|
|
803
|
+
)
|
|
804
|
+
|
|
794
805
|
@pytest.mark.asyncio
|
|
795
806
|
async def test_run_visibility_delegates_to_client(self, client: Client) -> None:
|
|
796
807
|
handle = WorkflowHandle(client, workflow_id="wf-1", run_id="r1", workflow_type="greeter")
|
|
@@ -3181,6 +3192,42 @@ class TestUpdateWorkflow:
|
|
|
3181
3192
|
|
|
3182
3193
|
|
|
3183
3194
|
class TestGetResult:
|
|
3195
|
+
@pytest.mark.asyncio
|
|
3196
|
+
async def test_completed_result_on_later_history_page(self, client: Client) -> None:
|
|
3197
|
+
handle = WorkflowHandle(client, workflow_id="wf-1", run_id="run-1", workflow_type="greeter")
|
|
3198
|
+
client.describe_workflow = AsyncMock(
|
|
3199
|
+
return_value=WorkflowExecution(
|
|
3200
|
+
workflow_id="wf-1", run_id="run-1", workflow_type="greeter", status="completed",
|
|
3201
|
+
)
|
|
3202
|
+
)
|
|
3203
|
+
client.get_history = AsyncMock(side_effect=[
|
|
3204
|
+
{"events": [{"event_type": "WorkflowStarted"}], "next_page_token": "page two"},
|
|
3205
|
+
{"events": [{"event_type": "WorkflowCompleted", "payload": {
|
|
3206
|
+
"output": serializer.encode(42, codec="avro"), "payload_codec": "avro",
|
|
3207
|
+
}}], "next_page_token": None},
|
|
3208
|
+
])
|
|
3209
|
+
|
|
3210
|
+
assert await client.get_result(handle) == 42
|
|
3211
|
+
assert client.get_history.await_args_list[0].args == ("wf-1", "run-1")
|
|
3212
|
+
assert client.get_history.await_args_list[0].kwargs == {"page_size": 1000, "next_page_token": None}
|
|
3213
|
+
assert client.get_history.await_args_list[1].kwargs == {
|
|
3214
|
+
"page_size": 1000, "next_page_token": "page two",
|
|
3215
|
+
}
|
|
3216
|
+
|
|
3217
|
+
@pytest.mark.asyncio
|
|
3218
|
+
async def test_repeated_history_page_token_fails(self, client: Client) -> None:
|
|
3219
|
+
handle = WorkflowHandle(client, workflow_id="wf-1", run_id="run-1", workflow_type="greeter")
|
|
3220
|
+
client.describe_workflow = AsyncMock(
|
|
3221
|
+
return_value=WorkflowExecution(
|
|
3222
|
+
workflow_id="wf-1", run_id="run-1", workflow_type="greeter", status="completed",
|
|
3223
|
+
)
|
|
3224
|
+
)
|
|
3225
|
+
client.get_history = AsyncMock(return_value={"events": [], "next_page_token": "same"})
|
|
3226
|
+
|
|
3227
|
+
with pytest.raises(RuntimeError, match="repeated a page token"):
|
|
3228
|
+
await client.get_result(handle)
|
|
3229
|
+
assert client.get_history.await_count == 2
|
|
3230
|
+
|
|
3184
3231
|
@pytest.mark.asyncio
|
|
3185
3232
|
async def test_completed_result_uses_event_payload_codec(self, client: Client) -> None:
|
|
3186
3233
|
handle = WorkflowHandle(client, workflow_id="wf-1", run_id="run-1", workflow_type="greeter")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
from pathlib import Path
|
|
3
|
-
from unittest.mock import AsyncMock
|
|
3
|
+
from unittest.mock import AsyncMock, patch
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
6
|
|
|
@@ -740,6 +740,26 @@ def test_fetch_external_payload_cache_reuses_verified_bytes(tmp_path: Path) -> N
|
|
|
740
740
|
assert len(cache) == 1
|
|
741
741
|
|
|
742
742
|
|
|
743
|
+
def test_default_cache_reuses_large_replay_reference_set(tmp_path: Path) -> None:
|
|
744
|
+
storage = LocalFilesystemExternalStorage(tmp_path)
|
|
745
|
+
cache = ExternalPayloadCache()
|
|
746
|
+
references = [
|
|
747
|
+
store_external_payload(storage, f"signal-{index}".encode(), codec="avro")
|
|
748
|
+
for index in range(1000)
|
|
749
|
+
]
|
|
750
|
+
|
|
751
|
+
with patch.object(storage, "get", wraps=storage.get) as get:
|
|
752
|
+
for _ in range(2):
|
|
753
|
+
for index, reference in enumerate(references):
|
|
754
|
+
assert fetch_external_payload(storage, reference, cache=cache) == (
|
|
755
|
+
f"signal-{index}".encode()
|
|
756
|
+
)
|
|
757
|
+
|
|
758
|
+
assert get.call_count == len(references)
|
|
759
|
+
assert len(cache) == len(references)
|
|
760
|
+
assert cache.current_bytes <= cache.max_bytes == 16 * 1024 * 1024
|
|
761
|
+
|
|
762
|
+
|
|
743
763
|
def test_delete_external_payload_removes_blob_and_cache_entry(tmp_path: Path) -> None:
|
|
744
764
|
storage = LocalFilesystemExternalStorage(tmp_path)
|
|
745
765
|
cache = ExternalPayloadCache(max_entries=2, max_bytes=1024)
|
|
@@ -28,7 +28,9 @@ async def test_persisted_deadline_raises_typed_timeout_for_selected_history(kind
|
|
|
28
28
|
try:
|
|
29
29
|
with pytest.raises(WorkflowTimedOut, match="workflow execution timed out"):
|
|
30
30
|
await client.get_result(handle, timeout=0)
|
|
31
|
-
client.get_history.assert_awaited_once_with(
|
|
31
|
+
client.get_history.assert_awaited_once_with(
|
|
32
|
+
"order", "selected-run", page_size=1000, next_page_token=None
|
|
33
|
+
)
|
|
32
34
|
finally:
|
|
33
35
|
await client.aclose()
|
|
34
36
|
|
|
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.4 → durable_workflow-2.3.6}/src/durable_workflow/external_task_input.py
RENAMED
|
File without changes
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow/external_task_result.py
RENAMED
|
File without changes
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/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.4 → durable_workflow-2.3.6}/src/durable_workflow/python_conformance.py
RENAMED
|
File without changes
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/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
|
|
File without changes
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/src/durable_workflow.egg-info/requires.txt
RENAMED
|
File without changes
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/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
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/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
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/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.4 → durable_workflow-2.3.6}/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
|
|
File without changes
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/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
|
{durable_workflow-2.3.4 → durable_workflow-2.3.6}/tests/test_workflow_updates_conformance.py
RENAMED
|
File without changes
|