From 7eeb7781537cd855367d94587b170a1cd3bcbf32 Mon Sep 17 00:00:00 2001 From: Andy Staples Date: Mon, 10 Aug 2026 10:26:28 -0600 Subject: [PATCH 1/2] Add orchestration query prefix filter Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: abe44a4b-db94-4661-bb3b-2d7dd30b1e78 --- CHANGELOG.md | 5 ++++ durabletask/client.py | 1 + durabletask/internal/client_helpers.py | 1 + tests/durabletask/test_batch_actions.py | 34 +++++++++++++++++++++++++ 4 files changed, 41 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d881ef7e..9e2e982c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +ADDED + +- Added `OrchestrationQuery.instance_id_prefix` to retrieve orchestration +instances whose IDs begin with a specified prefix. + ## v1.9.0 ADDED diff --git a/durabletask/client.py b/durabletask/client.py index a5974749..5f73b422 100644 --- a/durabletask/client.py +++ b/durabletask/client.py @@ -192,6 +192,7 @@ class OrchestrationQuery: created_time_from: datetime | None = None created_time_to: datetime | None = None runtime_status: list[OrchestrationStatus] | None = None + instance_id_prefix: str | None = None # Some backends don't respond well with max_instance_count = None, so we use the integer limit for non-paginated # results instead. max_instance_count: int | None = (1 << 31) - 1 diff --git a/durabletask/internal/client_helpers.py b/durabletask/internal/client_helpers.py index fe0c828b..d3c51181 100644 --- a/durabletask/internal/client_helpers.py +++ b/durabletask/internal/client_helpers.py @@ -103,6 +103,7 @@ def build_query_instances_req( runtimeStatus=[status.value for status in orchestration_query.runtime_status] if orchestration_query.runtime_status else None, createdTimeFrom=helpers.new_timestamp(orchestration_query.created_time_from) if orchestration_query.created_time_from else None, createdTimeTo=helpers.new_timestamp(orchestration_query.created_time_to) if orchestration_query.created_time_to else None, + instanceIdPrefix=helpers.get_string_value(orchestration_query.instance_id_prefix), maxInstanceCount=orchestration_query.max_instance_count, fetchInputsAndOutputs=orchestration_query.fetch_inputs_and_outputs, continuationToken=continuation_token diff --git a/tests/durabletask/test_batch_actions.py b/tests/durabletask/test_batch_actions.py index 65637df0..59b49eb0 100644 --- a/tests/durabletask/test_batch_actions.py +++ b/tests/durabletask/test_batch_actions.py @@ -12,6 +12,7 @@ import pytest from durabletask import client, entities, task from durabletask.client import TaskHubGrpcClient +from durabletask.internal.client_helpers import build_query_instances_req from durabletask.testing import create_test_backend from durabletask.worker import TaskHubGrpcWorker @@ -163,6 +164,39 @@ def test_get_orchestration_state_by_time_range(backend): assert len([o for o in orchestrations_outside_range if o.instance_id == id]) == 0 +def test_get_orchestration_state_by_instance_id_prefix(backend): + worker = TaskHubGrpcWorker(host_address=HOST) + + worker.add_orchestrator(empty_orchestrator) + worker.start() + + try: + with TaskHubGrpcClient(host_address=HOST) as c: + matching_id = "prefix-match" + non_matching_id = "other-instance" + c.schedule_new_orchestration(empty_orchestrator, instance_id=matching_id) + c.schedule_new_orchestration(empty_orchestrator, instance_id=non_matching_id) + c.wait_for_orchestration_completion(matching_id, timeout=30) + c.wait_for_orchestration_completion(non_matching_id, timeout=30) + + query = client.OrchestrationQuery(instance_id_prefix="prefix-") + orchestrations = c.get_all_orchestration_states(query) + finally: + worker.stop() + + assert [orchestration.instance_id for orchestration in orchestrations] == [matching_id] + + +def test_orchestration_query_serializes_instance_id_prefix(): + request = build_query_instances_req( + client.OrchestrationQuery(instance_id_prefix="prefix-"), + continuation_token=None, + ) + + assert request.query.HasField("instanceIdPrefix") + assert request.query.instanceIdPrefix.value == "prefix-" + + def test_get_orchestration_state_pagination_succeeds(backend): # Create a custom handler to capture log messages log_records = [] From 5d6c4f2bb2f5d0c77de1c6e97828657af57a7b51 Mon Sep 17 00:00:00 2001 From: Andy Staples Date: Thu, 13 Aug 2026 10:41:58 -0600 Subject: [PATCH 2/2] Address orchestration query review feedback Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: abe44a4b-db94-4661-bb3b-2d7dd30b1e78 --- azure-functions-durable/CHANGELOG.md | 5 +++++ durabletask-azuremanaged/CHANGELOG.md | 5 +++++ durabletask/client.py | 2 +- tests/durabletask/test_batch_actions.py | 8 ++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/azure-functions-durable/CHANGELOG.md b/azure-functions-durable/CHANGELOG.md index f5e4adf3..4d19faec 100644 --- a/azure-functions-durable/CHANGELOG.md +++ b/azure-functions-durable/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +ADDED + +- Added inherited `OrchestrationQuery.instance_id_prefix` support to retrieve +orchestration instances whose IDs begin with a specified prefix. + ## v2.0.0b2 ADDED diff --git a/durabletask-azuremanaged/CHANGELOG.md b/durabletask-azuremanaged/CHANGELOG.md index dde10137..6e671cd1 100644 --- a/durabletask-azuremanaged/CHANGELOG.md +++ b/durabletask-azuremanaged/CHANGELOG.md @@ -7,6 +7,11 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased +ADDED + +- Added inherited `OrchestrationQuery.instance_id_prefix` support to retrieve +orchestration instances whose IDs begin with a specified prefix. + ## v1.9.0 CHANGED diff --git a/durabletask/client.py b/durabletask/client.py index 5f73b422..b88df604 100644 --- a/durabletask/client.py +++ b/durabletask/client.py @@ -192,11 +192,11 @@ class OrchestrationQuery: created_time_from: datetime | None = None created_time_to: datetime | None = None runtime_status: list[OrchestrationStatus] | None = None - instance_id_prefix: str | None = None # Some backends don't respond well with max_instance_count = None, so we use the integer limit for non-paginated # results instead. max_instance_count: int | None = (1 << 31) - 1 fetch_inputs_and_outputs: bool = False + instance_id_prefix: str | None = None @dataclass diff --git a/tests/durabletask/test_batch_actions.py b/tests/durabletask/test_batch_actions.py index 59b49eb0..24989746 100644 --- a/tests/durabletask/test_batch_actions.py +++ b/tests/durabletask/test_batch_actions.py @@ -197,6 +197,14 @@ def test_orchestration_query_serializes_instance_id_prefix(): assert request.query.instanceIdPrefix.value == "prefix-" +def test_orchestration_query_preserves_positional_argument_order(): + query = client.OrchestrationQuery(None, None, None, None, True) + + assert query.max_instance_count is None + assert query.fetch_inputs_and_outputs is True + assert query.instance_id_prefix is None + + def test_get_orchestration_state_pagination_succeeds(backend): # Create a custom handler to capture log messages log_records = []