Skip to content

Commit 2af7b67

Browse files
jscudcopybara-github
authored andcommitted
feat: Populate X-Server-Timeout header when a request timeout is set.
PiperOrigin-RevId: 743955769
1 parent 5f3e895 commit 2af7b67

2 files changed

Lines changed: 86 additions & 10 deletions

File tree

google/genai/_api_client.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import io
2828
import json
2929
import logging
30+
import math
3031
import os
3132
import sys
3233
import time
@@ -97,6 +98,14 @@ def _patch_http_options(
9798
return copy_option
9899

99100

101+
def _populate_server_timeout_header(
102+
headers: dict[str, str], timeout_in_seconds: Optional[Union[float, int]]
103+
) -> None:
104+
"""Populates the server timeout header in the headers dict."""
105+
if timeout_in_seconds and 'X-Server-Timeout' not in headers:
106+
headers['X-Server-Timeout'] = str(math.ceil(timeout_in_seconds))
107+
108+
100109
def _join_url_path(base_url: str, path: str) -> str:
101110
parsed_base = urlparse(base_url)
102111
base_path = (
@@ -539,6 +548,9 @@ def _build_request(
539548

540549
if patched_http_options.headers is None:
541550
raise ValueError('Request headers must be set.')
551+
_populate_server_timeout_header(
552+
patched_http_options.headers, timeout_in_seconds
553+
)
542554
return HttpRequest(
543555
method=http_method,
544556
url=url,
@@ -795,14 +807,16 @@ def _upload_fd(
795807
else self._http_options.timeout
796808
)
797809
timeout_in_seconds = _get_timeout_in_seconds(timeout)
810+
upload_headers = {
811+
'X-Goog-Upload-Command': upload_command,
812+
'X-Goog-Upload-Offset': str(offset),
813+
'Content-Length': str(chunk_size),
814+
}
815+
_populate_server_timeout_header(upload_headers, timeout_in_seconds)
798816
response = self._httpx_client.request(
799817
method='POST',
800818
url=upload_url,
801-
headers={
802-
'X-Goog-Upload-Command': upload_command,
803-
'X-Goog-Upload-Offset': str(offset),
804-
'Content-Length': str(chunk_size),
805-
},
819+
headers=upload_headers,
806820
content=file_chunk,
807821
timeout=timeout_in_seconds,
808822
)
@@ -941,15 +955,17 @@ async def _async_upload_fd(
941955
else self._http_options.timeout
942956
)
943957
timeout_in_seconds = _get_timeout_in_seconds(timeout)
958+
upload_headers = {
959+
'X-Goog-Upload-Command': upload_command,
960+
'X-Goog-Upload-Offset': str(offset),
961+
'Content-Length': str(chunk_size),
962+
}
963+
_populate_server_timeout_header(upload_headers, timeout_in_seconds)
944964
response = await self._async_httpx_client.request(
945965
method='POST',
946966
url=upload_url,
947967
content=file_chunk,
948-
headers={
949-
'X-Goog-Upload-Command': upload_command,
950-
'X-Goog-Upload-Offset': str(offset),
951-
'Content-Length': str(chunk_size),
952-
},
968+
headers=upload_headers,
953969
timeout=timeout_in_seconds,
954970
)
955971
offset += chunk_size

google/genai/tests/client/test_http_options.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,63 @@ def test_patch_http_options_appends_version_headers():
7777
patched = _api_client._patch_http_options(original_options, patch_options)
7878
assert 'user-agent' in patched.headers
7979
assert 'x-goog-api-client' in patched.headers
80+
81+
82+
def test_setting_timeout_populates_server_timeout_header():
83+
api_client = _api_client.BaseApiClient(
84+
vertexai=False,
85+
api_key='test_api_key',
86+
http_options=types.HttpOptions(timeout=10000),
87+
)
88+
request = api_client._build_request(
89+
http_method='POST',
90+
path='sample/path',
91+
request_dict={},
92+
)
93+
assert 'X-Server-Timeout' in request.headers
94+
assert request.headers['X-Server-Timeout'] == '10'
95+
96+
97+
def test_timeout_rounded_to_nearest_second():
98+
api_client = _api_client.BaseApiClient(
99+
vertexai=False,
100+
api_key='test_api_key',
101+
)
102+
http_options = types.HttpOptions(timeout=7300)
103+
request = api_client._build_request(
104+
http_method='POST',
105+
path='sample/path',
106+
request_dict={},
107+
http_options=http_options,
108+
)
109+
assert request.headers['X-Server-Timeout'] == '8'
110+
111+
112+
def test_server_timeout_not_overwritten():
113+
api_client = _api_client.BaseApiClient(
114+
vertexai=False,
115+
api_key='test_api_key',
116+
)
117+
http_options = types.HttpOptions(
118+
headers={'X-Server-Timeout': '3'},
119+
timeout=11000)
120+
request = api_client._build_request(
121+
http_method='POST',
122+
path='sample/path',
123+
request_dict={},
124+
http_options=http_options,
125+
)
126+
assert request.headers['X-Server-Timeout'] == '3'
127+
128+
129+
def test_server_timeout_not_set_by_default():
130+
api_client = _api_client.BaseApiClient(
131+
vertexai=False,
132+
api_key='test_api_key',
133+
)
134+
request = api_client._build_request(
135+
http_method='POST',
136+
path='sample/path',
137+
request_dict={},
138+
)
139+
assert not 'X-Server-Timeout' in request.headers

0 commit comments

Comments
 (0)