Skip to content

Commit af2c37e

Browse files
Merge pull request #1174 from Kiln-AI/dchiang/KIL-498/add-copilot-timeout
Increase timeout for spec and add timeout error
2 parents 2e4f718 + ff19296 commit af2c37e

File tree

4 files changed

+49
-2
lines changed

4 files changed

+49
-2
lines changed

app/desktop/studio_server/api_client/kiln_server_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def get_authenticated_client(api_key: str) -> AuthenticatedClient:
4646
base_url=_get_base_url(),
4747
token=api_key,
4848
headers=_get_common_headers(),
49-
timeout=httpx.Timeout(timeout=300.0, connect=30.0),
49+
timeout=httpx.Timeout(timeout=900.0, connect=30.0),
5050
)
5151

5252

app/desktop/studio_server/api_client/test_kiln_server_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,5 +204,5 @@ def test_client_has_appropriate_timeout(self):
204204
"""Verify the client has a reasonable timeout for long-running requests."""
205205
client = get_authenticated_client("test_api_key")
206206
assert client._timeout is not None
207-
assert client._timeout.read == 300.0
207+
assert client._timeout.read == 900.0
208208
assert client._timeout.connect == 30.0

libs/server/kiln_server/custom_errors.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import logging
33

4+
import httpx
45
from fastapi import FastAPI, HTTPException, Request, status
56
from fastapi.exceptions import RequestValidationError
67
from fastapi.responses import JSONResponse
@@ -86,6 +87,18 @@ async def http_exception_handler(request: Request, exc: HTTPException):
8687
content={"message": exc.detail},
8788
)
8889

90+
@app.exception_handler(httpx.TimeoutException)
91+
async def timeout_error_handler(request: Request, exc: httpx.TimeoutException):
92+
logger.warning(
93+
f"Request timed out on {request.method} {request.url.path}",
94+
exc_info=exc,
95+
)
96+
return JSONResponse(
97+
status_code=status.HTTP_408_REQUEST_TIMEOUT,
98+
headers={"Access-Control-Allow-Origin": "*"},
99+
content={"message": "Request timed out. Please try again."},
100+
)
101+
89102
# Fallback error handler for any other exception
90103
@app.exception_handler(Exception)
91104
async def fallback_error_handler(request: Request, exc: Exception):

libs/server/kiln_server/test_custom_error.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import httpx
12
import pytest
23
from fastapi import FastAPI
34
from fastapi.testclient import TestClient
@@ -22,6 +23,14 @@ class Item(BaseModel):
2223
async def create_item(item: Item):
2324
return item
2425

26+
@app.get("/timeout")
27+
async def raise_timeout():
28+
raise httpx.TimeoutException("Request timed out")
29+
30+
@app.get("/generic-error")
31+
async def raise_generic_error():
32+
raise RuntimeError("Something went wrong")
33+
2534
return app
2635

2736

@@ -30,6 +39,11 @@ def client(app):
3039
return TestClient(app)
3140

3241

42+
@pytest.fixture
43+
def client_no_raise(app):
44+
return TestClient(app, raise_server_exceptions=False)
45+
46+
3347
def test_validation_error_single_field(client):
3448
response = client.post("/items", json={"name": "ab", "price": 10})
3549
assert response.status_code == 422
@@ -92,3 +106,23 @@ def test_format_error_loc_with_none():
92106

93107
def test_format_error_loc_with_empty_string():
94108
assert format_error_loc(("container", "", "field")) == "Container.Field"
109+
110+
111+
class TestTimeoutErrorHandler:
112+
def test_timeout_exception_returns_408(self, client_no_raise):
113+
response = client_no_raise.get("/timeout")
114+
assert response.status_code == 408
115+
116+
def test_timeout_exception_message(self, client_no_raise):
117+
response = client_no_raise.get("/timeout")
118+
body = response.json()
119+
assert body["message"] == "Request timed out. Please try again."
120+
assert "raw_error" not in body
121+
122+
def test_timeout_exception_has_cors_header(self, client_no_raise):
123+
response = client_no_raise.get("/timeout")
124+
assert response.headers.get("access-control-allow-origin") == "*"
125+
126+
def test_other_exceptions_still_return_500(self, client_no_raise):
127+
response = client_no_raise.get("/generic-error")
128+
assert response.status_code == 500

0 commit comments

Comments
 (0)