From 8d684c57c7aa8ccb387ed3e043e86676b39c8840 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Mon, 6 Jul 2026 13:36:43 +0000 Subject: [PATCH] =?UTF-8?q?Transient=20HubSpot=20failures=20are=20retried?= =?UTF-8?q?=20under=20the=20shared=20rate-limit=20policy=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- .../test_tenant_data_sync_orchestrator.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/orchestration/test_tenant_data_sync_orchestrator.py b/tests/orchestration/test_tenant_data_sync_orchestrator.py index 92dd4a885..6fd48e8ea 100644 --- a/tests/orchestration/test_tenant_data_sync_orchestrator.py +++ b/tests/orchestration/test_tenant_data_sync_orchestrator.py @@ -499,3 +499,32 @@ def test_run_fails_fast_when_association_fails_and_reports_the_orphaned_contact( assert "corr-abc-123" in str(error) # scrubbed diagnostics carried through assert "Solecka" not in rendered_traceback assert "09261195827" not in rendered_traceback + + +def test_run_retries_a_rate_limited_hubspot_call_before_succeeding( + orchestrator: TenantDataSyncOrchestrator, + mock_session: MagicMock, + sdk_client: MagicMock, +) -> None: + # Arrange + mock_session.post.return_value.content = _tenancy_response( + '1368473' + ) + rate_limited = ContactsApiException(status=429, reason="Too Many Requests") + rate_limited.headers = {"x-hubspot-ratelimit-interval-milliseconds": "0"} + sdk_client.crm.contacts.basic_api.create.side_effect = [ + rate_limited, + MagicMock(id="60123"), + ] + + # Act + result = orchestrator.run(PLACE_REF, deal_id=DEAL_ID) + + # Assert + assert result == TenantDataSyncSummary( + tenancy_reference="10042020051017", + contact_ids=("60123",), + vulnerable_contact_count=0, + ) + assert sdk_client.crm.contacts.basic_api.create.call_count == 2