Skip to content

Commit 2f0a89d

Browse files
GitHKAndrei Neagu
andauthored
🐛 use httpx to download output ports (#7824)
Co-authored-by: Andrei Neagu <[email protected]>
1 parent 3d8ae69 commit 2f0a89d

File tree

4 files changed

+53
-21
lines changed

4 files changed

+53
-21
lines changed

packages/simcore-sdk/requirements/_base.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
aiocache
1414
aiofiles
1515
aiohttp
16+
httpx
1617
packaging
1718
pint
18-
sqlalchemy[asyncio]
1919
pydantic[email]
20+
sqlalchemy[asyncio]
2021
tenacity
2122
tqdm

packages/simcore-sdk/requirements/_base.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ anyio==4.8.0
4444
# via
4545
# fast-depends
4646
# faststream
47+
# httpx
4748
arrow==1.3.0
4849
# via
4950
# -r requirements/../../../packages/models-library/requirements/_base.in
@@ -72,6 +73,8 @@ certifi==2025.1.31
7273
# -c requirements/../../../packages/settings-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt
7374
# -c requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt
7475
# -c requirements/../../../requirements/constraints.txt
76+
# httpcore
77+
# httpx
7578
# requests
7679
charset-normalizer==3.4.1
7780
# via requests
@@ -109,10 +112,32 @@ greenlet==3.1.1
109112
# via sqlalchemy
110113
grpcio==1.70.0
111114
# via opentelemetry-exporter-otlp-proto-grpc
115+
h11==0.16.0
116+
# via httpcore
117+
httpcore==1.0.9
118+
# via httpx
119+
httpx==0.28.1
120+
# via
121+
# -c requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt
122+
# -c requirements/../../../packages/models-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt
123+
# -c requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
124+
# -c requirements/../../../packages/postgres-database/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt
125+
# -c requirements/../../../packages/postgres-database/requirements/../../../requirements/constraints.txt
126+
# -c requirements/../../../packages/service-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt
127+
# -c requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt
128+
# -c requirements/../../../packages/service-library/requirements/../../../packages/models-library/requirements/../../../requirements/constraints.txt
129+
# -c requirements/../../../packages/service-library/requirements/../../../packages/settings-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt
130+
# -c requirements/../../../packages/service-library/requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt
131+
# -c requirements/../../../packages/service-library/requirements/../../../requirements/constraints.txt
132+
# -c requirements/../../../packages/settings-library/requirements/../../../packages/common-library/requirements/../../../requirements/constraints.txt
133+
# -c requirements/../../../packages/settings-library/requirements/../../../requirements/constraints.txt
134+
# -c requirements/../../../requirements/constraints.txt
135+
# -r requirements/_base.in
112136
idna==3.10
113137
# via
114138
# anyio
115139
# email-validator
140+
# httpx
116141
# requests
117142
# yarl
118143
importlib-metadata==8.5.0

packages/simcore-sdk/src/simcore_sdk/node_ports_common/file_io_utils.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
from typing import IO, Any, Final, Protocol, runtime_checkable
88

99
import aiofiles
10+
import httpx
1011
from aiohttp import (
1112
ClientConnectionError,
1213
ClientError,
13-
ClientPayloadError,
1414
ClientResponse,
1515
ClientResponseError,
1616
ClientSession,
@@ -39,6 +39,7 @@
3939
from tqdm.contrib.logging import tqdm_logging_redirect
4040
from yarl import URL
4141

42+
from ..config.http_clients import client_request_settings
4243
from . import exceptions
4344
from .constants import CHUNK_SIZE
4445

@@ -148,13 +149,13 @@ async def __call__(self, log: str) -> None: ...
148149

149150
async def _file_chunk_writer(
150151
file: Path,
151-
response: ClientResponse,
152+
response: httpx.Response,
152153
pbar: tqdm,
153154
io_log_redirect_cb: LogRedirectCB | None,
154155
progress_bar: ProgressBarData,
155156
):
156157
async with aiofiles.open(file, "wb") as file_pointer:
157-
while chunk := await response.content.read(CHUNK_SIZE):
158+
async for chunk in response.aiter_bytes(CHUNK_SIZE):
158159
await file_pointer.write(chunk)
159160
if io_log_redirect_cb and pbar.update(len(chunk)):
160161
with log_catch(_logger, reraise=False):
@@ -172,7 +173,6 @@ async def _file_chunk_writer(
172173

173174

174175
async def download_link_to_file(
175-
session: ClientSession,
176176
url: URL,
177177
file_path: Path,
178178
*,
@@ -185,16 +185,25 @@ async def download_link_to_file(
185185
reraise=True,
186186
wait=wait_exponential(min=1, max=10),
187187
stop=stop_after_attempt(num_retries),
188-
retry=retry_if_exception_type(ClientConnectionError),
188+
retry=retry_if_exception_type(httpx.TransportError),
189189
before_sleep=before_sleep_log(_logger, logging.WARNING, exc_info=True),
190190
after=after_log(_logger, log_level=logging.ERROR),
191191
):
192192
with attempt:
193193
async with AsyncExitStack() as stack:
194-
response = await stack.enter_async_context(session.get(url))
195-
if response.status == status.HTTP_404_NOT_FOUND:
194+
client = await stack.enter_async_context(
195+
httpx.AsyncClient(
196+
timeout=httpx.Timeout(
197+
client_request_settings.HTTP_CLIENT_REQUEST_TOTAL_TIMEOUT
198+
)
199+
)
200+
)
201+
response = await stack.enter_async_context(
202+
client.stream("GET", f"{url}")
203+
)
204+
if response.status_code == status.HTTP_404_NOT_FOUND:
196205
raise exceptions.InvalidDownloadLinkError(url)
197-
if response.status > _VALID_HTTP_STATUS_CODES:
206+
if response.status_code > _VALID_HTTP_STATUS_CODES:
198207
raise exceptions.TransferError(url)
199208
file_path.parent.mkdir(parents=True, exist_ok=True)
200209
# SEE https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length
@@ -231,7 +240,7 @@ async def download_link_to_file(
231240
sub_progress,
232241
)
233242
_logger.debug("Download complete")
234-
except ClientPayloadError as exc:
243+
except httpx.HTTPError as exc:
235244
raise exceptions.TransferError(url) from exc
236245

237246

packages/simcore-sdk/src/simcore_sdk/node_ports_common/filemanager.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ async def download_path_from_s3(
217217
return await download_file_from_link(
218218
download_link,
219219
local_path,
220-
client_session=session,
221220
io_log_redirect_cb=io_log_redirect_cb,
222221
progress_bar=progress_bar,
223222
)
@@ -229,7 +228,6 @@ async def download_file_from_link(
229228
*,
230229
io_log_redirect_cb: LogRedirectCB | None,
231230
file_name: str | None = None,
232-
client_session: ClientSession | None = None,
233231
progress_bar: ProgressBarData,
234232
) -> Path:
235233
# a download link looks something like:
@@ -242,15 +240,14 @@ async def download_file_from_link(
242240

243241
if io_log_redirect_cb:
244242
await io_log_redirect_cb(f"downloading {local_file_path}, please wait...")
245-
async with ClientSessionContextManager(client_session) as session:
246-
await download_link_to_file(
247-
session,
248-
download_link,
249-
local_file_path,
250-
num_retries=NodePortsSettings.create_from_envs().NODE_PORTS_IO_NUM_RETRY_ATTEMPTS,
251-
io_log_redirect_cb=io_log_redirect_cb,
252-
progress_bar=progress_bar,
253-
)
243+
244+
await download_link_to_file(
245+
download_link,
246+
local_file_path,
247+
num_retries=NodePortsSettings.create_from_envs().NODE_PORTS_IO_NUM_RETRY_ATTEMPTS,
248+
io_log_redirect_cb=io_log_redirect_cb,
249+
progress_bar=progress_bar,
250+
)
254251
if io_log_redirect_cb:
255252
await io_log_redirect_cb(f"download of {local_file_path} complete.")
256253
return local_file_path

0 commit comments

Comments
 (0)