mirror of
https://github.com/lancedb/lancedb.git
synced 2026-10-30 07:16:52 +00:00
fix(remote): make HTTP timeout errors actionable (#4650)
Remote `create_table` reader uploads can exceed the read deadline while waiting for response headers, but reqwest's main error message only says "error sending request". Make HTTP and retry errors explicitly identify timeouts and name the relevant `client_config.timeout_config` settings and environment variables, preserving typed sources, request metadata, and retry classification. Document that the read timeout covers waiting for headers during upload. This implements the issue's diagnostic option: creation still uses one streaming request, so large or slow readers may require a longer `client_config.timeout_config.read_timeout`. Validation: - 48 focused Rust client, error, and retry tests passed. Regression coverage holds an upload open until its read timeout and also exercises TLS connection timeouts, with and without retries. - 8 Python create-table and HTTP/retry error tests passed in the uv-managed environment after rebuilding the extension, including reader creation with read and overall timeouts. - `cargo check --quiet --features remote --tests --examples` passed. - `cargo clippy --quiet --features remote --tests --examples` passed. - Rust formatting and Python package Ruff lint/format checks passed. - Repository-wide `ruff check .` reports 49 existing findings under `docs/web-tests`; those files are unchanged. Fixes #4646 <!-- lance-gatekeeper-fix:v1 agent=ce1c040fa581f1748166ecb686d9c9c0 generation=1 --> --------- Co-authored-by: Gatefixer <313497061+lancedb-gatefixer[bot]@users.noreply.github.com> Co-authored-by: Xuanwo <github@xuanwo.io>
This commit is contained in:
co-authored by
Xuanwo
parent
ad1212fb32
commit
83b7275137
@@ -52,7 +52,10 @@ class TimeoutConfig:
|
||||
`LANCE_CLIENT_CONNECT_TIMEOUT`, as an integer number of seconds.
|
||||
read_timeout: Optional[timedelta]
|
||||
The timeout for reading data from the server. Default is 300 seconds
|
||||
(5 minutes). This can also be set via the environment variable
|
||||
(5 minutes). This also applies while waiting for response headers during
|
||||
an upload. Increase it for large or slowly produced inputs to
|
||||
`create_table`, even if data is still being uploaded. This can also be
|
||||
set via the environment variable
|
||||
`LANCE_CLIENT_READ_TIMEOUT`, as an integer number of seconds.
|
||||
pool_idle_timeout: Optional[timedelta]
|
||||
The timeout for keeping idle connections in the connection pool. Default
|
||||
|
||||
@@ -811,6 +811,43 @@ def test_create_table_exist_ok_with_mode_overwrite():
|
||||
assert table is not None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize(
|
||||
"timeout_config",
|
||||
[{"read_timeout": 0.5}, {"timeout": 0.5, "read_timeout": 5}],
|
||||
)
|
||||
async def test_create_table_timeout_is_actionable(timeout_config):
|
||||
release_response = threading.Event()
|
||||
received = {}
|
||||
|
||||
def handler(request):
|
||||
received["path"] = request.path
|
||||
received["request_id"] = request.headers["x-request-id"]
|
||||
release_response.wait(timeout=5)
|
||||
request.close_connection = True
|
||||
|
||||
async with mock_lancedb_connection_async(
|
||||
handler, timeout_config=timeout_config
|
||||
) as db:
|
||||
batch = pa.record_batch({"id": [1, 2]})
|
||||
reader = pa.RecordBatchReader.from_batches(batch.schema, [batch])
|
||||
try:
|
||||
with pytest.raises(HttpError) as exc_info:
|
||||
await db.create_table("test", reader)
|
||||
finally:
|
||||
release_response.set()
|
||||
|
||||
error = exc_info.value
|
||||
assert "timed out" in str(error)
|
||||
assert "client_config.timeout_config.read_timeout" in str(error)
|
||||
assert "client_config.timeout_config.timeout" in str(error)
|
||||
assert "LANCE_CLIENT_READ_TIMEOUT" in str(error)
|
||||
assert received["path"] == "/v1/table/test/create/?mode=create"
|
||||
assert error.request_id == received["request_id"]
|
||||
assert error.status_code is None
|
||||
assert isinstance(error.__cause__, HttpError)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_http_error():
|
||||
request_id_holder = {"request_id": None}
|
||||
|
||||
Reference in New Issue
Block a user