durable-workflow 2.5.7__tar.gz → 2.5.8__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.
Files changed (129) hide show
  1. {durable_workflow-2.5.7/src/durable_workflow.egg-info → durable_workflow-2.5.8}/PKG-INFO +1 -1
  2. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/pyproject.toml +3 -3
  3. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/worker.py +7 -0
  4. {durable_workflow-2.5.7 → durable_workflow-2.5.8/src/durable_workflow.egg-info}/PKG-INFO +1 -1
  5. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_worker.py +31 -1
  6. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/LICENSE +0 -0
  7. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/README.md +0 -0
  8. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/setup.cfg +0 -0
  9. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/__init__.py +0 -0
  10. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/_activity_process.py +0 -0
  11. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/_avro.py +0 -0
  12. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/_cancellation_scope.py +0 -0
  13. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/_cancellation_scope_history.py +0 -0
  14. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/_cooperative_cancellation.py +0 -0
  15. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/_prepared_local_activity.py +0 -0
  16. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/_sticky_workflow_cache.py +0 -0
  17. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/activity.py +0 -0
  18. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/auth_composition.py +0 -0
  19. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/cancellation.py +0 -0
  20. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/client.py +0 -0
  21. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/errors.py +0 -0
  22. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/external_storage.py +0 -0
  23. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/external_task_input.py +0 -0
  24. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/external_task_result.py +0 -0
  25. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/history_bundle_verify.py +0 -0
  26. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/interceptors.py +0 -0
  27. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/invocable.py +0 -0
  28. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/metrics.py +0 -0
  29. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/nexus.py +0 -0
  30. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/py.typed +0 -0
  31. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/python_conformance.py +0 -0
  32. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/replay_conformance.py +0 -0
  33. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/replay_verify.py +0 -0
  34. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/retry_policy.py +0 -0
  35. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/serializer.py +0 -0
  36. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/sync.py +0 -0
  37. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/testing.py +0 -0
  38. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/worker_session.py +0 -0
  39. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/workflow.py +0 -0
  40. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow/workflow_updates_conformance.py +0 -0
  41. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow.egg-info/SOURCES.txt +0 -0
  42. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow.egg-info/dependency_links.txt +0 -0
  43. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow.egg-info/entry_points.txt +0 -0
  44. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow.egg-info/requires.txt +0 -0
  45. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/src/durable_workflow.egg-info/top_level.txt +0 -0
  46. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_activity_cancellation_policies.py +0 -0
  47. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_activity_context.py +0 -0
  48. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_activity_process.py +0 -0
  49. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_auth_composition.py +0 -0
  50. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_avro_value_benchmark.py +0 -0
  51. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_avro_value_protocol.py +0 -0
  52. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_cancellation_context.py +0 -0
  53. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_cancellation_remaining_time.py +0 -0
  54. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_cancellation_scope_admission.py +0 -0
  55. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_cancellation_scope_authoring.py +0 -0
  56. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_cancellation_scope_boundary.py +0 -0
  57. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_cancellation_scope_opening.py +0 -0
  58. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_child_workflow_policies.py +0 -0
  59. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_ci_checkout.py +0 -0
  60. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_ci_integration_endpoint.py +0 -0
  61. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_client.py +0 -0
  62. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_client_timeouts.py +0 -0
  63. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_codec_regression_corpus.py +0 -0
  64. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_committed_cancellation_scope_descendants.py +0 -0
  65. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_committed_cancellation_scope_groups.py +0 -0
  66. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_committed_cancellation_scope_history.py +0 -0
  67. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_committed_cancellation_scope_replay.py +0 -0
  68. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_condition_replay_drift.py +0 -0
  69. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_control_plane_parity_fixtures.py +0 -0
  70. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_cooperative_cancellation.py +0 -0
  71. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_cooperative_cancellation_client.py +0 -0
  72. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_cooperative_cancellation_worker.py +0 -0
  73. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_cooperative_remote_worker.py +0 -0
  74. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_docstring_cross_references.py +0 -0
  75. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_durable_selection.py +0 -0
  76. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_errors.py +0 -0
  77. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_external_storage.py +0 -0
  78. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_external_task_input.py +0 -0
  79. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_external_task_result.py +0 -0
  80. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_golden_history_replay.py +0 -0
  81. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_history_bundle_verify.py +0 -0
  82. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_history_event_contract.py +0 -0
  83. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_invocable.py +0 -0
  84. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_message_streams.py +0 -0
  85. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_metrics.py +0 -0
  86. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_nexus_namespace.py +0 -0
  87. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_nexus_wire.py +0 -0
  88. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_order_processing_example.py +0 -0
  89. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_parallel_completion_order_replay.py +0 -0
  90. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_parallel_saga_authoring.py +0 -0
  91. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_patch_history.py +0 -0
  92. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_pending_operation_replay.py +0 -0
  93. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_prepared_local_activity_client.py +0 -0
  94. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_prepared_local_activity_groups.py +0 -0
  95. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_prepared_local_activity_policies.py +0 -0
  96. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_prepared_local_activity_worker.py +0 -0
  97. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_public_boundary_scanner.py +0 -0
  98. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_pypi_project_surface.py +0 -0
  99. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_python_conformance.py +0 -0
  100. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_queries.py +0 -0
  101. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_readme_quickstart.py +0 -0
  102. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_redrive_replay.py +0 -0
  103. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_registration_ambiguity.py +0 -0
  104. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_release_metadata.py +0 -0
  105. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_replay.py +0 -0
  106. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_replay_conformance.py +0 -0
  107. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_replay_regression_corpus.py +0 -0
  108. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_replay_verify.py +0 -0
  109. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_retry_policy.py +0 -0
  110. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_run_cancellation_scope_replay.py +0 -0
  111. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_runtime_external_payload_transport.py +0 -0
  112. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_schedules.py +0 -0
  113. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_scoped_run_cancellation_context.py +0 -0
  114. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_serializer.py +0 -0
  115. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_signals.py +0 -0
  116. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_sleep.py +0 -0
  117. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_standalone_activity_client.py +0 -0
  118. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_sticky_execution.py +0 -0
  119. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_storage_admission.py +0 -0
  120. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_sync.py +0 -0
  121. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_testing_harness.py +0 -0
  122. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_update_signal_condition_replay.py +0 -0
  123. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_updates.py +0 -0
  124. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_wait_condition.py +0 -0
  125. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_worker_session.py +0 -0
  126. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_workflow_entrypoint_validation.py +0 -0
  127. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_workflow_result_timeout.py +0 -0
  128. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_workflow_streams.py +0 -0
  129. {durable_workflow-2.5.7 → durable_workflow-2.5.8}/tests/test_workflow_updates_conformance.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: durable-workflow
3
- Version: 2.5.7
3
+ Version: 2.5.8
4
4
  Summary: Python client and worker SDK for Durable Workflow Cloud and self-hosted Server
5
5
  Author: Durable Workflow Contributors
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "durable-workflow"
7
- version = "2.5.7"
7
+ version = "2.5.8"
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.5.7"
75
- registry-version = "2.5.7"
74
+ product-train = "2.5.8"
75
+ registry-version = "2.5.8"
76
76
  supported-server-versions = "2.5.16"
77
77
  worker-protocol-version = "1.20"
78
78
  control-plane-version = "2"
@@ -4244,6 +4244,7 @@ class Worker:
4244
4244
  """
4245
4245
  background_tasks: list[asyncio.Task[Any]] = []
4246
4246
  deadline = asyncio.get_running_loop().time() + timeout
4247
+ startup_completed = False
4247
4248
 
4248
4249
  self._begin_run()
4249
4250
  try:
@@ -4252,6 +4253,7 @@ class Worker:
4252
4253
  finally:
4253
4254
  self._registration_done.set()
4254
4255
 
4256
+ startup_completed = True
4255
4257
  if self._stop.is_set():
4256
4258
  raise asyncio.CancelledError
4257
4259
  background_tasks.append(asyncio.create_task(self._heartbeat_loop()))
@@ -4273,6 +4275,11 @@ class Worker:
4273
4275
  run_until_loop, timeout=max(0.0, deadline - asyncio.get_running_loop().time()),
4274
4276
  )
4275
4277
  except asyncio.TimeoutError as error:
4278
+ if not startup_completed:
4279
+ raise TimeoutError(
4280
+ f"worker {self.worker_id} startup did not finish within the "
4281
+ f"{timeout}s workflow wait budget for {workflow_id}"
4282
+ ) from error
4276
4283
  raise TimeoutError(f"workflow {workflow_id} not terminal after {timeout}s") from error
4277
4284
  finally:
4278
4285
  primary_error = sys.exc_info()[1]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: durable-workflow
3
- Version: 2.5.7
3
+ Version: 2.5.8
4
4
  Summary: Python client and worker SDK for Durable Workflow Cloud and self-hosted Server
5
5
  Author: Durable Workflow Contributors
6
6
  License-Expression: MIT
@@ -5101,6 +5101,34 @@ class TestRunUntil:
5101
5101
  assert mock_client.describe_workflow.await_count == 2
5102
5102
  assert mock_client.poll_workflow_task.call_args.kwargs["history_page_size"] == 500
5103
5103
 
5104
+ @pytest.mark.asyncio
5105
+ @pytest.mark.parametrize("blocked_method", ["get_cluster_info", "register_worker"])
5106
+ async def test_run_until_identifies_startup_timeout_before_polling(
5107
+ self, mock_client: AsyncMock, blocked_method: str
5108
+ ) -> None:
5109
+ started = asyncio.Event()
5110
+
5111
+ async def blocked(*args: object, **kwargs: object) -> None:
5112
+ started.set()
5113
+ await asyncio.Event().wait()
5114
+
5115
+ setattr(mock_client, blocked_method, AsyncMock(side_effect=blocked))
5116
+ worker = Worker(mock_client, task_queue="q1", workflows=[TestWorkflow])
5117
+
5118
+ with pytest.raises(TimeoutError) as failure:
5119
+ await worker.run_until(workflow_id="wf-startup-timeout", timeout=0.05)
5120
+
5121
+ assert started.is_set()
5122
+ assert "startup" in str(failure.value)
5123
+ assert worker.worker_id in str(failure.value)
5124
+ assert "wf-startup-timeout" in str(failure.value)
5125
+ assert isinstance(failure.value.__cause__, asyncio.TimeoutError)
5126
+ assert worker._stop.is_set()
5127
+ assert worker._registration_done.is_set()
5128
+ mock_client.poll_workflow_task.assert_not_awaited()
5129
+ mock_client.poll_activity_task.assert_not_awaited()
5130
+ mock_client.deregister_worker_registration.assert_not_awaited()
5131
+
5104
5132
  @pytest.mark.asyncio
5105
5133
  async def test_run_until_times_out_and_stops_worker(self, mock_client: AsyncMock) -> None:
5106
5134
  mock_client.describe_workflow = AsyncMock(
@@ -5119,9 +5147,11 @@ class TestRunUntil:
5119
5147
  poll_timeout=0.01,
5120
5148
  )
5121
5149
 
5122
- with pytest.raises(TimeoutError, match="wf-timeout"):
5150
+ with pytest.raises(TimeoutError, match="wf-timeout") as failure:
5123
5151
  await worker.run_until(workflow_id="wf-timeout", timeout=0.02, poll_interval=0.01)
5124
5152
 
5153
+ assert "not terminal" in str(failure.value)
5154
+ assert "startup" not in str(failure.value)
5125
5155
  assert worker._stop.is_set()
5126
5156
 
5127
5157
  @pytest.mark.asyncio