durable-workflow 2.11.0__tar.gz → 2.11.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.
- {durable_workflow-2.11.0/src/durable_workflow.egg-info → durable_workflow-2.11.1}/PKG-INFO +1 -1
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/pyproject.toml +3 -3
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/worker.py +67 -9
- {durable_workflow-2.11.0 → durable_workflow-2.11.1/src/durable_workflow.egg-info}/PKG-INFO +1 -1
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_worker.py +228 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/LICENSE +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/README.md +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/setup.cfg +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/__init__.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_activity_lease.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_activity_process.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_avro.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_cancellation_scope.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_cancellation_scope_history.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_cooperative_cancellation.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_failure_reporting.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_metric_routes.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_prepared_local_activity.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_query_task_authority.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_sticky_workflow_cache.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/activity.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/auth_composition.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/cancellation.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/client.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/errors.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/external_storage.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/external_task_input.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/external_task_result.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/history_bundle_verify.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/interceptors.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/invocable.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/metrics.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/nexus.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/py.typed +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/python_conformance.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/replay_conformance.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/replay_verify.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/retry_policy.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/serializer.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/sync.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/telemetry.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/telemetry_carrier.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/testing.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/worker_session.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/workflow.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/workflow_updates_conformance.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow.egg-info/SOURCES.txt +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow.egg-info/dependency_links.txt +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow.egg-info/entry_points.txt +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow.egg-info/requires.txt +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow.egg-info/top_level.txt +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_activity_cancellation_policies.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_activity_context.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_activity_heartbeat_authority.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_activity_lease_authority.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_activity_lease_renewal.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_activity_lease_worker.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_activity_process.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_auth_composition.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_avro_value_benchmark.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_avro_value_protocol.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_context.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_remaining_time.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_scope_admission.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_scope_authoring.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_scope_boundary.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_scope_opening.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_child_workflow_policies.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_ci_checkout.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_ci_integration_endpoint.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_client.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_client_telemetry.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_client_timeouts.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_codec_regression_corpus.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_committed_cancellation_scope_descendants.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_committed_cancellation_scope_groups.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_committed_cancellation_scope_history.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_committed_cancellation_scope_replay.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_condition_replay_drift.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_control_plane_parity_fixtures.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cooperative_cancellation.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cooperative_cancellation_client.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cooperative_cancellation_worker.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cooperative_remote_worker.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_docstring_cross_references.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_durable_selection.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_errors.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_external_storage.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_external_task_input.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_external_task_result.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_failure_reporting.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_golden_history_replay.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_history_bundle_schema2.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_history_bundle_verify.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_history_event_contract.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_invocable.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_local_failure_reporting.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_message_streams.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_metric_routes.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_metrics.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_nexus_durable_wait.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_nexus_namespace.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_nexus_wire.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_order_processing_example.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_parallel_completion_order_replay.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_parallel_saga_authoring.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_patch_history.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_pending_operation_replay.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_poll_failure_backoff.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_prepared_local_activity_client.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_prepared_local_activity_groups.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_prepared_local_activity_policies.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_prepared_local_activity_worker.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_public_boundary_scanner.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_pypi_project_surface.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_python_conformance.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_queries.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_query_task_authority.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_query_timeout_retry.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_readme_quickstart.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_redrive_replay.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_registration_ambiguity.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_release_metadata.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_replay.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_replay_clock.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_replay_conformance.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_replay_regression_corpus.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_replay_verify.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_retry_policy.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_run_cancellation_scope_replay.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_runtime_external_payload_transport.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_schedules.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_scoped_run_cancellation_context.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_sdk_metrics_contract.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_serializer.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_signals.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_sleep.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_standalone_activity_client.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_sticky_execution.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_storage_admission.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_sync.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_sync_activities.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_telemetry.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_telemetry_carrier.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_testing_failures.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_testing_harness.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_testing_nexus.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_threaded_heartbeat_example.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_tls_trust.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_transport_diagnostics.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_update_signal_condition_replay.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_updates.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_wait_condition.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_worker_deregistration.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_worker_observation.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_worker_session.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_worker_telemetry_wire.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_workflow_entry_arguments.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_workflow_entrypoint_validation.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_workflow_handler_validation.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_workflow_identity.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_workflow_result_timeout.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_workflow_streams.py +0 -0
- {durable_workflow-2.11.0 → durable_workflow-2.11.1}/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.11.
|
|
7
|
+
version = "2.11.1"
|
|
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"
|
|
@@ -76,8 +76,8 @@ durable-workflow-replay-conformance = "durable_workflow.replay_conformance:main"
|
|
|
76
76
|
durable-workflow-workflow-updates-conformance = "durable_workflow.workflow_updates_conformance:main"
|
|
77
77
|
|
|
78
78
|
[tool.durable-workflow]
|
|
79
|
-
product-train = "2.11.
|
|
80
|
-
registry-version = "2.11.
|
|
79
|
+
product-train = "2.11.1"
|
|
80
|
+
registry-version = "2.11.1"
|
|
81
81
|
supported-server-versions = "2.8.0"
|
|
82
82
|
worker-protocol-version = "1.20"
|
|
83
83
|
control-plane-version = "2"
|
|
@@ -259,8 +259,8 @@ class _PollFailureBackoff:
|
|
|
259
259
|
self._last_summary: str | None = None
|
|
260
260
|
self._last_warning_at = 0.0
|
|
261
261
|
|
|
262
|
-
def retry_delay(self, error: Exception, task_kind: str) -> float:
|
|
263
|
-
delay = random.uniform(self._ceiling / 2, self._ceiling)
|
|
262
|
+
def retry_delay(self, error: Exception, task_kind: str, *, minimum_delay: float = 0.0) -> float:
|
|
263
|
+
delay = max(minimum_delay, random.uniform(self._ceiling / 2, self._ceiling))
|
|
264
264
|
self._ceiling = min(30.0, self._ceiling * 2)
|
|
265
265
|
summary = _poll_error_summary(error)
|
|
266
266
|
now = time.monotonic()
|
|
@@ -280,6 +280,28 @@ def _poll_capacity_delay(error: BaseException, task_kind: str, task_queue: str)
|
|
|
280
280
|
return error.poll_capacity_backpressure_delay(task_kind, task_queue)
|
|
281
281
|
|
|
282
282
|
|
|
283
|
+
def _backend_lock_poll_delay(
|
|
284
|
+
error: Exception, task_kind: str, task_queue: str, namespace: object,
|
|
285
|
+
) -> int | None:
|
|
286
|
+
if not isinstance(error, ServerError) or error.status != 503:
|
|
287
|
+
return None
|
|
288
|
+
body = error.body
|
|
289
|
+
if (
|
|
290
|
+
not isinstance(body, dict) or not isinstance(namespace, str) or not namespace
|
|
291
|
+
or body.get("reason") != "backend_lock_pressure"
|
|
292
|
+
or body.get("poll_status") != "backend_lock_pressure"
|
|
293
|
+
or "task" not in body or body["task"] is not None
|
|
294
|
+
or body.get("task_kind") != task_kind + "_task"
|
|
295
|
+
or body.get("task_queue") != task_queue or body.get("namespace") != namespace
|
|
296
|
+
or ("retryable" in body and body["retryable"] is not True)
|
|
297
|
+
or ("request_admitted" in body and body["request_admitted"] is not False)
|
|
298
|
+
or type(body.get("retry_after_seconds")) is not int
|
|
299
|
+
or not 0 < body["retry_after_seconds"] <= 60
|
|
300
|
+
):
|
|
301
|
+
return None
|
|
302
|
+
return int(body["retry_after_seconds"])
|
|
303
|
+
|
|
304
|
+
|
|
283
305
|
def _command_payload_codec(codec: object) -> str:
|
|
284
306
|
if codec is None:
|
|
285
307
|
return serializer.AVRO_CODEC
|
|
@@ -4468,6 +4490,7 @@ class Worker:
|
|
|
4468
4490
|
) -> WorkflowExecution:
|
|
4469
4491
|
deadline = time.monotonic() + timeout
|
|
4470
4492
|
next_task_kind = "workflow"
|
|
4493
|
+
failures = {"workflow": _PollFailureBackoff(), "activity": _PollFailureBackoff()}
|
|
4471
4494
|
|
|
4472
4495
|
while not self._stop.is_set():
|
|
4473
4496
|
desc = await self.client.describe_workflow(workflow_id)
|
|
@@ -4494,9 +4517,14 @@ class Worker:
|
|
|
4494
4517
|
task_kinds=self._workflow_poll_task_kinds(),
|
|
4495
4518
|
history_page_size=WORKFLOW_HISTORY_PAGE_SIZE,
|
|
4496
4519
|
)
|
|
4497
|
-
except BaseException:
|
|
4520
|
+
except BaseException as error:
|
|
4498
4521
|
self._release_workflow_capacity()
|
|
4522
|
+
if isinstance(error, Exception) and await self._retry_run_until_poll_refusal(
|
|
4523
|
+
error, "workflow", poll_start, deadline, failures["workflow"],
|
|
4524
|
+
):
|
|
4525
|
+
continue
|
|
4499
4526
|
raise
|
|
4527
|
+
failures["workflow"].reset()
|
|
4500
4528
|
if self._stop.is_set():
|
|
4501
4529
|
self._release_workflow_capacity()
|
|
4502
4530
|
raise asyncio.CancelledError
|
|
@@ -4543,12 +4571,20 @@ class Worker:
|
|
|
4543
4571
|
await asyncio.sleep(poll_interval)
|
|
4544
4572
|
continue
|
|
4545
4573
|
poll_start = time.perf_counter()
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4574
|
+
try:
|
|
4575
|
+
task = await self.client.poll_activity_task(
|
|
4576
|
+
worker_id=self.worker_id,
|
|
4577
|
+
task_queue=self.task_queue,
|
|
4578
|
+
timeout=self._poll_timeout,
|
|
4579
|
+
build_id=self.build_id,
|
|
4580
|
+
)
|
|
4581
|
+
except Exception as error:
|
|
4582
|
+
if await self._retry_run_until_poll_refusal(
|
|
4583
|
+
error, "activity", poll_start, deadline, failures["activity"],
|
|
4584
|
+
):
|
|
4585
|
+
continue
|
|
4586
|
+
raise
|
|
4587
|
+
failures["activity"].reset()
|
|
4552
4588
|
if self._stop.is_set():
|
|
4553
4589
|
raise asyncio.CancelledError
|
|
4554
4590
|
self._record_poll_metrics(
|
|
@@ -4566,6 +4602,28 @@ class Worker:
|
|
|
4566
4602
|
|
|
4567
4603
|
raise asyncio.CancelledError
|
|
4568
4604
|
|
|
4605
|
+
async def _retry_run_until_poll_refusal(
|
|
4606
|
+
self, error: Exception, kind: str, poll_start: float, deadline: float,
|
|
4607
|
+
failures: _PollFailureBackoff,
|
|
4608
|
+
) -> bool:
|
|
4609
|
+
delay = _backend_lock_poll_delay(
|
|
4610
|
+
error, kind, self.task_queue, getattr(self.client, "namespace", None),
|
|
4611
|
+
)
|
|
4612
|
+
if delay is None:
|
|
4613
|
+
return False
|
|
4614
|
+
self._record_poll_metrics(kind, "error", time.perf_counter() - poll_start)
|
|
4615
|
+
backoff = failures.retry_delay(error, kind, minimum_delay=delay)
|
|
4616
|
+
remaining = deadline - time.monotonic()
|
|
4617
|
+
if remaining <= 0:
|
|
4618
|
+
raise asyncio.TimeoutError
|
|
4619
|
+
# Both the public caller timer and this local wait retain their original
|
|
4620
|
+
# deadline. Stop interrupts the backoff without another poll or dispatch.
|
|
4621
|
+
with contextlib.suppress(asyncio.TimeoutError):
|
|
4622
|
+
await asyncio.wait_for(self._stop.wait(), timeout=min(backoff, remaining))
|
|
4623
|
+
if time.monotonic() >= deadline:
|
|
4624
|
+
raise asyncio.TimeoutError
|
|
4625
|
+
return True
|
|
4626
|
+
|
|
4569
4627
|
async def _run_until_activity_task(self, task: dict[str, Any]) -> None:
|
|
4570
4628
|
task_start = time.perf_counter()
|
|
4571
4629
|
outcome = "error"
|
|
@@ -2,9 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import contextlib
|
|
5
|
+
import json
|
|
5
6
|
import logging
|
|
6
7
|
import sys
|
|
7
8
|
import threading
|
|
9
|
+
from pathlib import Path
|
|
8
10
|
from unittest.mock import AsyncMock, Mock
|
|
9
11
|
|
|
10
12
|
import httpx
|
|
@@ -5029,6 +5031,232 @@ class TestWorkerHeartbeats:
|
|
|
5029
5031
|
|
|
5030
5032
|
|
|
5031
5033
|
class TestRunUntil:
|
|
5034
|
+
@pytest.mark.asyncio
|
|
5035
|
+
async def test_lock_refusal_then_cold_history_preserves_original_activity_result(
|
|
5036
|
+
self, mock_client: AsyncMock,
|
|
5037
|
+
) -> None:
|
|
5038
|
+
from tests.test_poll_failure_backoff import RecoveredWorkflow
|
|
5039
|
+
|
|
5040
|
+
fixture = json.loads((Path(__file__).parent / "fixtures/replay_regressions/"
|
|
5041
|
+
"run-until-lock-refusal-cold-history.json").read_text())
|
|
5042
|
+
mock_client.namespace = "default"
|
|
5043
|
+
mock_client.get_cluster_info.return_value = compatible_cluster_info(worker_protocol={
|
|
5044
|
+
"version": PROTOCOL_VERSION,
|
|
5045
|
+
"server_capabilities": {"query_tasks": False, "long_poll_timeout": 30},
|
|
5046
|
+
})
|
|
5047
|
+
run_id = fixture["workflow"]["run_id"]
|
|
5048
|
+
completed = False
|
|
5049
|
+
|
|
5050
|
+
async def describe(workflow_id: str) -> WorkflowExecution:
|
|
5051
|
+
return WorkflowExecution(
|
|
5052
|
+
workflow_id, run_id, fixture["workflow"]["type"], "completed" if completed else "running",
|
|
5053
|
+
)
|
|
5054
|
+
|
|
5055
|
+
async def complete(**kwargs: object) -> dict[str, str]:
|
|
5056
|
+
nonlocal completed
|
|
5057
|
+
completed = True
|
|
5058
|
+
return {"outcome": "completed"}
|
|
5059
|
+
|
|
5060
|
+
mock_client.describe_workflow.side_effect = describe
|
|
5061
|
+
mock_client.complete_workflow_task.side_effect = complete
|
|
5062
|
+
mock_client.poll_workflow_task.side_effect = [ServerError(503, {
|
|
5063
|
+
"task": None, "poll_status": "backend_lock_pressure", "reason": "backend_lock_pressure",
|
|
5064
|
+
"namespace": "default", "task_queue": "orders", "task_kind": "workflow_task",
|
|
5065
|
+
"retry_after_seconds": 1,
|
|
5066
|
+
}), {
|
|
5067
|
+
"task_id": "original-cold-task", "workflow_task_attempt": 3,
|
|
5068
|
+
"workflow_type": fixture["workflow"]["type"], "workflow_id": "order-0",
|
|
5069
|
+
"run_id": run_id, "payload_codec": "avro",
|
|
5070
|
+
"arguments": serializer.encode(fixture["workflow"]["input"]), "history_events": fixture["history"],
|
|
5071
|
+
}]
|
|
5072
|
+
worker = Worker(
|
|
5073
|
+
mock_client, task_queue="orders", workflows=[RecoveredWorkflow],
|
|
5074
|
+
max_concurrent_workflow_tasks=1, poll_timeout=0.01,
|
|
5075
|
+
)
|
|
5076
|
+
execution = await worker.run_until(workflow_id="order-0", timeout=3.0, poll_interval=0.01)
|
|
5077
|
+
assert execution.run_id == run_id
|
|
5078
|
+
assert execution.status == "completed"
|
|
5079
|
+
mock_client.complete_workflow_task.assert_awaited_once()
|
|
5080
|
+
publication = mock_client.complete_workflow_task.call_args.kwargs
|
|
5081
|
+
assert publication["task_id"] == "original-cold-task"
|
|
5082
|
+
assert publication["workflow_task_attempt"] == 3
|
|
5083
|
+
commands = publication["commands"]
|
|
5084
|
+
assert len(commands) == 1
|
|
5085
|
+
assert commands[0]["type"] == "complete_workflow"
|
|
5086
|
+
assert serializer.decode_envelope(commands[0]["result"], codec="avro") == fixture["expected"]["result"]
|
|
5087
|
+
mock_client.complete_activity_task.assert_not_awaited()
|
|
5088
|
+
mock_client.fail_workflow_task.assert_not_awaited()
|
|
5089
|
+
assert worker._workflow_reserved == 0
|
|
5090
|
+
|
|
5091
|
+
def refusal_worker(
|
|
5092
|
+
self, client: AsyncMock, kind: str,
|
|
5093
|
+
) -> tuple[Worker, AsyncMock, dict[str, object]]:
|
|
5094
|
+
client.namespace = "default"
|
|
5095
|
+
client.get_cluster_info.return_value = compatible_cluster_info(worker_protocol={
|
|
5096
|
+
"version": PROTOCOL_VERSION,
|
|
5097
|
+
"server_capabilities": {"query_tasks": False, "long_poll_timeout": 30},
|
|
5098
|
+
})
|
|
5099
|
+
client.describe_workflow.return_value = WorkflowExecution(
|
|
5100
|
+
"original", "original-run", "test-wf", "running",
|
|
5101
|
+
)
|
|
5102
|
+
body: dict[str, object] = {
|
|
5103
|
+
"task": None, "poll_status": "backend_lock_pressure", "reason": "backend_lock_pressure",
|
|
5104
|
+
"namespace": "default", "task_queue": "orders", "task_kind": kind + "_task",
|
|
5105
|
+
"retry_after_seconds": 1,
|
|
5106
|
+
}
|
|
5107
|
+
worker = Worker(
|
|
5108
|
+
client, worker_id="w1", task_queue="orders",
|
|
5109
|
+
workflows=[TestWorkflow] if kind == "workflow" else [],
|
|
5110
|
+
activities=[echo_activity] if kind == "activity" else [], poll_timeout=0.01,
|
|
5111
|
+
max_concurrent_workflow_tasks=1,
|
|
5112
|
+
)
|
|
5113
|
+
return worker, getattr(client, "poll_" + kind + "_task"), body
|
|
5114
|
+
|
|
5115
|
+
@pytest.mark.asyncio
|
|
5116
|
+
@pytest.mark.parametrize("kind", ["workflow", "activity"])
|
|
5117
|
+
@pytest.mark.parametrize("registration_delay", [0.0, 0.04])
|
|
5118
|
+
async def test_run_until_lock_pressure_retains_original_deadline(
|
|
5119
|
+
self, mock_client: AsyncMock, kind: str, registration_delay: float,
|
|
5120
|
+
) -> None:
|
|
5121
|
+
worker, poll, body = self.refusal_worker(mock_client, kind)
|
|
5122
|
+
poll.side_effect = ServerError(503, body)
|
|
5123
|
+
|
|
5124
|
+
async def register(**kwargs: object) -> dict[str, object]:
|
|
5125
|
+
await asyncio.sleep(registration_delay)
|
|
5126
|
+
return {"worker_id": "w1", "registered": True}
|
|
5127
|
+
|
|
5128
|
+
mock_client.register_worker.side_effect = register
|
|
5129
|
+
started = asyncio.get_running_loop().time()
|
|
5130
|
+
with pytest.raises(TimeoutError, match="original"):
|
|
5131
|
+
await worker.run_until(workflow_id="original", timeout=0.08, poll_interval=0.01)
|
|
5132
|
+
elapsed = asyncio.get_running_loop().time() - started
|
|
5133
|
+
|
|
5134
|
+
assert 0.06 <= elapsed < 1.0
|
|
5135
|
+
poll.assert_awaited_once()
|
|
5136
|
+
assert worker._stop.is_set()
|
|
5137
|
+
mock_client.deregister_worker_registration.assert_awaited_once_with("w1", expected_namespace="default")
|
|
5138
|
+
|
|
5139
|
+
@pytest.mark.asyncio
|
|
5140
|
+
@pytest.mark.parametrize("kind", ["workflow", "activity"])
|
|
5141
|
+
async def test_run_until_stop_interrupts_lock_backoff(
|
|
5142
|
+
self, mock_client: AsyncMock, kind: str,
|
|
5143
|
+
) -> None:
|
|
5144
|
+
worker, poll, body = self.refusal_worker(mock_client, kind)
|
|
5145
|
+
entered = asyncio.Event()
|
|
5146
|
+
|
|
5147
|
+
async def refuse(**kwargs: object) -> None:
|
|
5148
|
+
entered.set()
|
|
5149
|
+
raise ServerError(503, body)
|
|
5150
|
+
|
|
5151
|
+
poll.side_effect = refuse
|
|
5152
|
+
running = asyncio.create_task(worker.run_until(workflow_id="original", timeout=5.0))
|
|
5153
|
+
await asyncio.wait_for(entered.wait(), timeout=1.0)
|
|
5154
|
+
await asyncio.sleep(0)
|
|
5155
|
+
await asyncio.wait_for(worker.stop(), timeout=0.5)
|
|
5156
|
+
with pytest.raises(asyncio.CancelledError):
|
|
5157
|
+
await running
|
|
5158
|
+
|
|
5159
|
+
poll.assert_awaited_once()
|
|
5160
|
+
mock_client.complete_workflow_task.assert_not_awaited()
|
|
5161
|
+
mock_client.complete_activity_task.assert_not_awaited()
|
|
5162
|
+
mock_client.deregister_worker_registration.assert_awaited_once_with("w1", expected_namespace="default")
|
|
5163
|
+
|
|
5164
|
+
@pytest.mark.asyncio
|
|
5165
|
+
@pytest.mark.parametrize("kind", ["workflow", "activity"])
|
|
5166
|
+
@pytest.mark.parametrize("change", [
|
|
5167
|
+
{"task_queue": "foreign"}, {"task_kind": "query_task"}, {"task": {"task_id": "claimed"}},
|
|
5168
|
+
{"poll_status": "empty"}, {"retry_after_seconds": True}, {"retry_after_seconds": 61},
|
|
5169
|
+
{"retryable": False}, {"request_admitted": True},
|
|
5170
|
+
])
|
|
5171
|
+
async def test_run_until_refuses_malformed_or_admitted_poll_response(
|
|
5172
|
+
self, mock_client: AsyncMock, kind: str, change: dict[str, object],
|
|
5173
|
+
) -> None:
|
|
5174
|
+
worker, poll, body = self.refusal_worker(mock_client, kind)
|
|
5175
|
+
refusal = ServerError(503, {**body, **change})
|
|
5176
|
+
poll.side_effect = refusal
|
|
5177
|
+
with pytest.raises(ServerError) as observed:
|
|
5178
|
+
await worker.run_until(workflow_id="original", timeout=2.0)
|
|
5179
|
+
assert observed.value is refusal
|
|
5180
|
+
poll.assert_awaited_once()
|
|
5181
|
+
mock_client.complete_workflow_task.assert_not_awaited()
|
|
5182
|
+
mock_client.complete_activity_task.assert_not_awaited()
|
|
5183
|
+
|
|
5184
|
+
@pytest.mark.asyncio
|
|
5185
|
+
@pytest.mark.parametrize("kind", ["workflow", "activity"])
|
|
5186
|
+
async def test_run_until_recovers_typed_lock_refusal(
|
|
5187
|
+
self, mock_client: AsyncMock, kind: str,
|
|
5188
|
+
) -> None:
|
|
5189
|
+
mock_client.namespace = "default"
|
|
5190
|
+
mock_client.get_cluster_info.return_value = compatible_cluster_info(worker_protocol={
|
|
5191
|
+
"version": PROTOCOL_VERSION,
|
|
5192
|
+
"server_capabilities": {"query_tasks": False, "long_poll_timeout": 30},
|
|
5193
|
+
})
|
|
5194
|
+
mock_client.describe_workflow.side_effect = [
|
|
5195
|
+
WorkflowExecution("original", "original-run", "test-wf", "running"),
|
|
5196
|
+
WorkflowExecution("original", "original-run", "test-wf", "running"),
|
|
5197
|
+
WorkflowExecution("original", "original-run", "test-wf", "completed"),
|
|
5198
|
+
]
|
|
5199
|
+
refusal = ServerError(503, {
|
|
5200
|
+
"task": None, "poll_status": "backend_lock_pressure", "reason": "backend_lock_pressure",
|
|
5201
|
+
"namespace": "default", "task_queue": "orders", "task_kind": kind + "_task",
|
|
5202
|
+
"retry_after_seconds": 1, "backend": {"driver": "sqlite", "lock_pressure": True},
|
|
5203
|
+
})
|
|
5204
|
+
poll = getattr(mock_client, "poll_" + kind + "_task")
|
|
5205
|
+
poll.side_effect = [refusal, None]
|
|
5206
|
+
worker = Worker(
|
|
5207
|
+
mock_client, worker_id="w1", task_queue="orders",
|
|
5208
|
+
workflows=[TestWorkflow] if kind == "workflow" else [],
|
|
5209
|
+
activities=[echo_activity] if kind == "activity" else [],
|
|
5210
|
+
poll_timeout=0.01,
|
|
5211
|
+
max_concurrent_workflow_tasks=1,
|
|
5212
|
+
)
|
|
5213
|
+
|
|
5214
|
+
execution = await worker.run_until(workflow_id="original", timeout=2.0, poll_interval=0.01)
|
|
5215
|
+
|
|
5216
|
+
assert execution.status == "completed"
|
|
5217
|
+
assert execution.run_id == "original-run"
|
|
5218
|
+
assert poll.await_count == 2
|
|
5219
|
+
assert all(call.kwargs["worker_id"] == "w1" for call in poll.await_args_list)
|
|
5220
|
+
assert all(call.kwargs["task_queue"] == "orders" for call in poll.await_args_list)
|
|
5221
|
+
mock_client.register_worker.assert_awaited_once()
|
|
5222
|
+
mock_client.deregister_worker_registration.assert_awaited_once_with("w1", expected_namespace="default")
|
|
5223
|
+
mock_client.complete_workflow_task.assert_not_awaited()
|
|
5224
|
+
mock_client.complete_activity_task.assert_not_awaited()
|
|
5225
|
+
|
|
5226
|
+
@pytest.mark.asyncio
|
|
5227
|
+
@pytest.mark.parametrize("kind", ["workflow", "activity"])
|
|
5228
|
+
@pytest.mark.parametrize("refusal_kind", ["foreign_namespace", "unauthorized"])
|
|
5229
|
+
async def test_run_until_preserves_fatal_or_foreign_poll_refusal(
|
|
5230
|
+
self, mock_client: AsyncMock, kind: str, refusal_kind: str,
|
|
5231
|
+
) -> None:
|
|
5232
|
+
mock_client.namespace = "default"
|
|
5233
|
+
mock_client.get_cluster_info.return_value = compatible_cluster_info(worker_protocol={
|
|
5234
|
+
"version": PROTOCOL_VERSION,
|
|
5235
|
+
"server_capabilities": {"query_tasks": False, "long_poll_timeout": 30},
|
|
5236
|
+
})
|
|
5237
|
+
mock_client.describe_workflow.return_value = WorkflowExecution(
|
|
5238
|
+
"original", "original-run", "test-wf", "running",
|
|
5239
|
+
)
|
|
5240
|
+
refusal = Unauthorized() if refusal_kind == "unauthorized" else ServerError(503, {
|
|
5241
|
+
"task": None, "poll_status": "backend_lock_pressure", "reason": "backend_lock_pressure",
|
|
5242
|
+
"namespace": "foreign", "task_queue": "orders", "task_kind": kind + "_task",
|
|
5243
|
+
"retry_after_seconds": 1,
|
|
5244
|
+
})
|
|
5245
|
+
poll = getattr(mock_client, "poll_" + kind + "_task")
|
|
5246
|
+
poll.side_effect = refusal
|
|
5247
|
+
worker = Worker(
|
|
5248
|
+
mock_client, worker_id="w1", task_queue="orders",
|
|
5249
|
+
workflows=[TestWorkflow] if kind == "workflow" else [],
|
|
5250
|
+
activities=[echo_activity] if kind == "activity" else [], poll_timeout=0.01,
|
|
5251
|
+
)
|
|
5252
|
+
|
|
5253
|
+
with pytest.raises(type(refusal)) as observed:
|
|
5254
|
+
await worker.run_until(workflow_id="original", timeout=2.0, poll_interval=0.01)
|
|
5255
|
+
|
|
5256
|
+
assert observed.value is refusal
|
|
5257
|
+
poll.assert_awaited_once()
|
|
5258
|
+
mock_client.deregister_worker_registration.assert_awaited_once_with("w1", expected_namespace="default")
|
|
5259
|
+
|
|
5032
5260
|
@pytest.mark.asyncio
|
|
5033
5261
|
@pytest.mark.parametrize("has_workflows,has_activities", [(True, False), (False, True), (False, False)])
|
|
5034
5262
|
async def test_run_until_polls_only_registered_task_families(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_activity_process.py
RENAMED
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_cancellation_scope.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_failure_reporting.py
RENAMED
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_prepared_local_activity.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_query_task_authority.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/_sticky_workflow_cache.py
RENAMED
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/auth_composition.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/external_storage.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/external_task_input.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/external_task_result.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/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.11.0 → durable_workflow-2.11.1}/src/durable_workflow/python_conformance.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/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
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow/telemetry_carrier.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow.egg-info/requires.txt
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/src/durable_workflow.egg-info/top_level.txt
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_activity_cancellation_policies.py
RENAMED
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_activity_heartbeat_authority.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.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_remaining_time.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_scope_admission.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_scope_authoring.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_scope_boundary.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cancellation_scope_opening.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.11.0 → durable_workflow-2.11.1}/tests/test_control_plane_parity_fixtures.py
RENAMED
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cooperative_cancellation_client.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_cooperative_cancellation_worker.py
RENAMED
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_docstring_cross_references.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_parallel_completion_order_replay.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_prepared_local_activity_client.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_prepared_local_activity_groups.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_prepared_local_activity_policies.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_prepared_local_activity_worker.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_run_cancellation_scope_replay.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_runtime_external_payload_transport.py
RENAMED
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_scoped_run_cancellation_context.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_standalone_activity_client.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.11.0 → durable_workflow-2.11.1}/tests/test_threaded_heartbeat_example.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/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
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_workflow_entrypoint_validation.py
RENAMED
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_workflow_handler_validation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{durable_workflow-2.11.0 → durable_workflow-2.11.1}/tests/test_workflow_updates_conformance.py
RENAMED
|
File without changes
|