-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Add timeouts to remote downloads #418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,36 +4,50 @@ | |
| import os | ||
| from .settings import _DEFAULT_FOLDER_, _MODEL_VERSION_, _ONLINE_URL_, _REMOTE_URL_, onnx_model_maps, onnx_runtime_config | ||
|
|
||
| REQUEST_TIMEOUT_SECONDS = 30 | ||
|
|
||
|
|
||
| def down_model_file(url, save_path): | ||
| resp = requests.get(url, stream=True) | ||
| resp = requests.get(url, stream=True, timeout=REQUEST_TIMEOUT_SECONDS) | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Self-review: The shared timeout constant keeps model file and zip downloads consistent, and raise_for_status prevents streaming an error page into the model cache. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The More importantly, if the server accepts the connection and starts sending but stalls mid-transfer (e.g. after the first few chunks), the 30s read timeout will eventually fire and raise def down_model_file(url, save_path):
resp = requests.get(url, stream=True, timeout=REQUEST_TIMEOUT_SECONDS)
resp.raise_for_status()
total = int(resp.headers.get('content-length', 0))
try:
with open(save_path, 'wb') as file, tqdm(...) as bar:
for data in resp.iter_content(chunk_size=1024):
size = file.write(data)
bar.update(size)
except Exception:
if os.path.exists(save_path):
os.remove(save_path)
raiseSame applies to actionsFeedback: Rate this comment to help me improve future code reviews:
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, accepted in 8323c2b by removing partially written model files if streaming fails before re-raising the download error. |
||
| resp.raise_for_status() | ||
| total = int(resp.headers.get('content-length', 0)) | ||
| with open(save_path, 'wb') as file, tqdm( | ||
| desc="Pull", | ||
| total=total, | ||
| unit='iB', | ||
| unit_scale=True, | ||
| unit_divisor=1024, | ||
| ) as bar: | ||
| for data in resp.iter_content(chunk_size=1024): | ||
| size = file.write(data) | ||
| bar.update(size) | ||
| try: | ||
| with open(save_path, 'wb') as file, tqdm( | ||
| desc="Pull", | ||
| total=total, | ||
| unit='iB', | ||
| unit_scale=True, | ||
| unit_divisor=1024, | ||
| ) as bar: | ||
| for data in resp.iter_content(chunk_size=1024): | ||
| size = file.write(data) | ||
| bar.update(size) | ||
| except Exception: | ||
| if os.path.exists(save_path): | ||
| os.remove(save_path) | ||
| raise | ||
|
|
||
|
|
||
| def down_model_zip(url, save_path, is_unzip=False): | ||
| resp = requests.get(url, stream=True) | ||
| resp = requests.get(url, stream=True, timeout=REQUEST_TIMEOUT_SECONDS) | ||
| resp.raise_for_status() | ||
| total = int(resp.headers.get('content-length', 0)) | ||
| name = os.path.join(save_path, os.path.basename(url)) | ||
| with open(name, 'wb') as file, tqdm( | ||
| desc="Pull", | ||
| total=total, | ||
| unit='iB', | ||
| unit_scale=True, | ||
| unit_divisor=1024, | ||
| ) as bar: | ||
| for data in resp.iter_content(chunk_size=1024): | ||
| size = file.write(data) | ||
| bar.update(size) | ||
| try: | ||
| with open(name, 'wb') as file, tqdm( | ||
| desc="Pull", | ||
| total=total, | ||
| unit='iB', | ||
| unit_scale=True, | ||
| unit_divisor=1024, | ||
| ) as bar: | ||
| for data in resp.iter_content(chunk_size=1024): | ||
| size = file.write(data) | ||
| bar.update(size) | ||
| except Exception: | ||
| if os.path.exists(name): | ||
| os.remove(name) | ||
| raise | ||
|
|
||
| if is_unzip: | ||
| f = zipfile.ZipFile(name, "r") | ||
|
|
@@ -60,4 +74,3 @@ def initialization(re_download=False): | |
| if not os.path.exists(models_dir) or re_download: | ||
| target_url = os.path.join(_ONLINE_URL_, _MODEL_VERSION_) + '.zip' | ||
| down_model_zip(target_url, _DEFAULT_FOLDER_, True) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The broad
except Exceptionsilently swallows the newurllib.error.URLError(raised on timeout) and returnsNone, giving the caller no indication of why it failed. Now that a timeout is a real code path, at least log a warning:Note:
import urllibalone does not makeurllib.erroravailable — it must be imported explicitly.actions
Feedback: Rate this comment to help me improve future code reviews:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, accepted in 8323c2b by importing urllib.request/urllib.error explicitly and logging URL fetch failures before returning None.