diff --git a/changelog/fixed/tiptoeing-terrapin.md b/changelog/fixed/tiptoeing-terrapin.md new file mode 100644 index 000000000..6d5bcc718 --- /dev/null +++ b/changelog/fixed/tiptoeing-terrapin.md @@ -0,0 +1 @@ +Send a request ID when terminating a standalone activity, so a retried `ActivityHandle.terminate()` call no longer fails after the first attempt already terminated the activity. diff --git a/temporalio/client/_impl.py b/temporalio/client/_impl.py index 3986f9e82..b8864c4e7 100644 --- a/temporalio/client/_impl.py +++ b/temporalio/client/_impl.py @@ -687,6 +687,7 @@ async def terminate_activity(self, input: TerminateActivityInput) -> None: run_id=input.activity_run_id or "", reason=input.reason or "", identity=self._client.identity, + request_id=str(uuid.uuid4()), ), retry=True, metadata=input.rpc_metadata, diff --git a/tests/test_activity.py b/tests/test_activity.py index b3208d951..b17d587d8 100644 --- a/tests/test_activity.py +++ b/tests/test_activity.py @@ -112,6 +112,25 @@ async def test_start_activity_generates_request_id() -> None: assert requests[0].request_id != requests[1].request_id +async def test_terminate_activity_generates_request_id() -> None: + terminate_activity_execution = mock.AsyncMock( + return_value=temporalio.api.workflowservice.v1.TerminateActivityExecutionResponse() + ) + service_client = mock.MagicMock() + service_client.config.identity = "test-identity" + service_client.workflow_service.terminate_activity_execution = ( + terminate_activity_execution + ) + client = Client(service_client) + + for activity_id in ("activity-id-1", "activity-id-2"): + await client.get_activity_handle(activity_id).terminate(reason="done") + + requests = [call.args[0] for call in terminate_activity_execution.call_args_list] + assert all(uuid.UUID(request.request_id).version == 4 for request in requests) + assert requests[0].request_id != requests[1].request_id + + class TestDescribe: @pytest.fixture def task_queue(self):