feat(client): default request_timeout applied at the REST seam#41
Conversation
The generated SDK sends _request_timeout=None (urllib3 no-timeout) on every call unless a caller passes one per call — and the helper methods (load_managed_table, list_managed_tables, ...) expose no such knob — so a stalled or black-holed server blocks the calling thread indefinitely, and the configured urllib3 read retries never fire because no read timeout ever triggers them. HotdataClient (and ManagedDatabaseClient, passing through) now accept request_timeout: seconds or a (connect, read) pair, installed once at construction by wrapping rest_client.request to default the per-call _request_timeout. Explicit per-call values still win; the default stays None so existing behavior is unchanged unless opted in. A construction- time deadline means stalled calls fail at the socket and the connection tears down — no caller-side thread tricks, and new call sites are bounded by construction.
| def request_with_default_timeout( | ||
| method, | ||
| url, | ||
| headers=None, | ||
| body=None, | ||
| post_params=None, | ||
| _request_timeout=None, | ||
| ): |
There was a problem hiding this comment.
nit: (not blocking) This nested function is fully unannotated (params + return), which trips this repo's strict mypy config (disallow_untyped_defs = true). Relatedly, rest_client.request = request_with_default_timeout on line 111 will trigger mypy's [method-assign] ("cannot assign to a method"). CI only runs pytest so the build isn't broken, but the rest of the codebase is strict-mypy clean, so this is a regression against that bar. Consider annotating the signature and adding # type: ignore[method-assign] on the assignment.
Separately, hard-coding the full method, url, headers, body, post_params, _request_timeout signature couples this wrapper to the exact generated RESTClientObject.request shape — a future SDK regeneration that adds a parameter would silently break (dropped kwarg or TypeError). Forwarding via *args, **kwargs (defaulting _request_timeout when absent/None) would survive regeneration.
|
|
||
|
|
||
|
|
There was a problem hiding this comment.
super nit: (not blocking) Three blank lines here — ruff (E303, which this repo selects) wants at most two between top-level definitions. Drop one.
There was a problem hiding this comment.
Approving. The wrapper correctly targets the REST seam, is invoked as a plain instance attribute (so the no-self signature is right), preserves explicit per-call _request_timeout, and the tests cover the real paths. Left two non-blocking nits (strict-mypy typing gap + wrapper signature coupling; an E303 blank-line).
The generated SDK sends _request_timeout=None (urllib3 no-timeout) on
every call unless a caller passes one per call — and the helper methods
(load_managed_table, list_managed_tables, ...) expose no such knob — so
a stalled or black-holed server blocks the calling thread indefinitely,
and the configured urllib3 read retries never fire because no read
timeout ever triggers them.
HotdataClient (and ManagedDatabaseClient, passing through) now accept
request_timeout: seconds or a (connect, read) pair, installed once at
construction by wrapping rest_client.request to default the per-call
_request_timeout. Explicit per-call values still win; the default stays
None so existing behavior is unchanged unless opted in. A construction-
time deadline means stalled calls fail at the socket and the connection
tears down — no caller-side thread tricks, and new call sites are
bounded by construction.