From d1e5d84878802c2b80cd8aa321b87c84b465f163 Mon Sep 17 00:00:00 2001 From: Sabiha Khan Date: Tue, 21 Jul 2026 19:06:20 +0530 Subject: [PATCH] fix: handle workflow run update failures --- api/routes/public_agent.py | 14 +++-- api/tests/test_public_agent_routes.py | 78 +++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 4 deletions(-) diff --git a/api/routes/public_agent.py b/api/routes/public_agent.py index 4814d6ab..2e6abf5d 100644 --- a/api/routes/public_agent.py +++ b/api/routes/public_agent.py @@ -345,10 +345,16 @@ async def _execute_resolved_target( if target.identifier_type == "trigger_path": gathered_context["trigger_uuid"] = target.identifier_value - await db_client.update_workflow_run( - run_id=workflow_run.id, - gathered_context=gathered_context, - ) + try: + await db_client.update_workflow_run( + run_id=workflow_run.id, + gathered_context=gathered_context, + ) + except Exception as e: + logger.warning( + f"Call initiated for workflow run {workflow_run.id}, but failed to " + f"persist provider metadata: {e}" + ) logger.info( f"Call initiated successfully for workflow run {workflow_run.id} " diff --git a/api/tests/test_public_agent_routes.py b/api/tests/test_public_agent_routes.py index d9336359..1167fe1c 100644 --- a/api/tests/test_public_agent_routes.py +++ b/api/tests/test_public_agent_routes.py @@ -307,6 +307,15 @@ def test_trigger_test_route_uses_draft_and_template_context_with_api_override(): assert create_kwargs["initial_context"]["age"] == 10 assert create_kwargs["initial_context"]["rank"] == 2 assert create_kwargs["initial_context"]["trigger_mode"] == "test" + mock_db.update_workflow_run.assert_awaited_once_with( + run_id=501, + gathered_context={ + "provider": "twilio", + "triggered_by": "api", + "call_id": "CA123", + "trigger_uuid": "trigger-uuid-123", + }, + ) def test_workflow_uuid_test_route_uses_draft_and_template_context(): @@ -374,6 +383,75 @@ def test_workflow_uuid_test_route_uses_draft_and_template_context(): assert create_kwargs["initial_context"]["age"] == 12 assert create_kwargs["initial_context"]["rank"] == 2 assert create_kwargs["initial_context"]["trigger_mode"] == "test" + mock_db.update_workflow_run.assert_awaited_once_with( + run_id=501, + gathered_context={ + "provider": "twilio", + "triggered_by": "api", + "call_id": "CA123", + }, + ) + + +def test_trigger_route_still_returns_success_when_metadata_persistence_fails(): + app = _make_test_app() + client = TestClient(app) + + workflow = _active_workflow(trigger_path="trigger-uuid-123") + provider = _provider() + quota_mock = AsyncMock( + return_value=SimpleNamespace(has_quota=True, error_message="") + ) + + with ( + patch("api.routes.public_agent.db_client") as mock_db, + patch("api.routes.public_agent.call_concurrency") as mock_concurrency, + patch( + "api.routes.public_agent.authorize_workflow_run_start", + new=quota_mock, + ), + patch( + "api.routes.public_agent.get_default_telephony_provider", + new=AsyncMock(return_value=provider), + ), + patch( + "api.routes.public_agent.get_backend_endpoints", + new=AsyncMock(return_value=("https://api.example.com", "wss://ignored")), + ), + ): + slot = object() + mock_concurrency.acquire_org_slot = AsyncMock(return_value=slot) + mock_concurrency.bind_workflow_run = AsyncMock() + mock_concurrency.release_workflow_run_slot = AsyncMock() + mock_concurrency.release_slot = AsyncMock() + + mock_db.validate_api_key = AsyncMock( + return_value=SimpleNamespace(id=7, organization_id=11, created_by=22) + ) + mock_db.get_agent_trigger_by_path = AsyncMock( + return_value=SimpleNamespace( + workflow_id=workflow.id, + organization_id=11, + state="active", + ) + ) + mock_db.get_workflow = AsyncMock(return_value=workflow) + mock_db.get_default_telephony_configuration = AsyncMock( + return_value=SimpleNamespace(id=55) + ) + mock_db.create_workflow_run = AsyncMock(return_value=SimpleNamespace(id=501)) + mock_db.update_workflow_run = AsyncMock(side_effect=Exception("db down")) + + response = client.post( + "/public/agent/trigger-uuid-123", + headers={"X-API-Key": "test-api-key"}, + json={"phone_number": "+15551234567"}, + ) + + assert response.status_code == 200 + provider.initiate_call.assert_awaited_once() + mock_db.update_workflow_run.assert_awaited_once() + mock_concurrency.release_workflow_run_slot.assert_not_awaited() def test_trigger_route_rejects_when_concurrency_limit_reached():