|
21 | 21 | ) |
22 | 22 | from fastapi.responses import JSONResponse, PlainTextResponse |
23 | 23 | from filelock import FileLock |
| 24 | +from filelock import Timeout as FileLockTimeout |
24 | 25 | from starlette.requests import HTTPConnection, Request |
25 | 26 | from starlette.types import ASGIApp, Receive, Scope, Send |
26 | 27 |
|
@@ -207,48 +208,55 @@ def __fetch_model_as_file( |
207 | 208 | ) -> str: |
208 | 209 | result_path = download_options.pop("save_path", urlparse(model_path).path.split("/")[-1]) |
209 | 210 | tmp_path = result_path + ".tmp" |
210 | | - with FileLock(result_path + ".lock", timeout=7200), niquests.get(model_path, stream=True) as response: |
211 | | - if not response.ok: |
212 | | - raise ModelFetchError( |
213 | | - f"Downloading of '{model_path}' failed, returned ({response.status_code}) {response.text}" |
214 | | - ) |
215 | | - downloaded_size = 0 |
216 | | - linked_etag = "" |
217 | | - for each_history in response.history: |
218 | | - linked_etag = each_history.headers.get("X-Linked-ETag", "") |
219 | | - if linked_etag: |
220 | | - break |
221 | | - if not linked_etag: |
222 | | - linked_etag = response.headers.get("X-Linked-ETag", response.headers.get("ETag", "")) |
223 | | - total_size = int(response.headers.get("Content-Length")) |
224 | | - try: |
225 | | - existing_size = os.path.getsize(result_path) |
226 | | - except OSError: |
227 | | - existing_size = 0 |
228 | | - if linked_etag and total_size == existing_size: |
229 | | - with builtins.open(result_path, "rb") as file: |
230 | | - sha256_hash = hashlib.sha256() |
231 | | - for byte_block in iter(lambda: file.read(4096), b""): |
232 | | - sha256_hash.update(byte_block) |
233 | | - if f'"{sha256_hash.hexdigest()}"' == linked_etag: |
234 | | - nc.set_init_status(min(current_progress + progress_for_task, 99)) |
235 | | - return result_path |
236 | | - |
237 | | - try: |
238 | | - with builtins.open(tmp_path, "wb") as file: |
239 | | - last_progress = current_progress |
240 | | - for chunk in response.iter_raw(-1): |
241 | | - downloaded_size += file.write(chunk) |
242 | | - if total_size: |
243 | | - new_progress = min(current_progress + int(progress_for_task * downloaded_size / total_size), 99) |
244 | | - if new_progress != last_progress: |
245 | | - nc.set_init_status(new_progress) |
246 | | - last_progress = new_progress |
247 | | - os.replace(tmp_path, result_path) |
248 | | - except BaseException: |
249 | | - if os.path.exists(tmp_path): |
250 | | - os.remove(tmp_path) |
251 | | - raise |
| 211 | + try: |
| 212 | + with FileLock(result_path + ".lock", timeout=7200), niquests.get(model_path, stream=True) as response: |
| 213 | + if not response.ok: |
| 214 | + raise ModelFetchError( |
| 215 | + f"Downloading of '{model_path}' failed, returned ({response.status_code}) {response.text}" |
| 216 | + ) |
| 217 | + downloaded_size = 0 |
| 218 | + linked_etag = "" |
| 219 | + for redirect_resp in response.history: |
| 220 | + linked_etag = redirect_resp.headers.get("X-Linked-ETag", "") |
| 221 | + if linked_etag: |
| 222 | + break |
| 223 | + if not linked_etag: |
| 224 | + linked_etag = response.headers.get("X-Linked-ETag", response.headers.get("ETag", "")) |
| 225 | + total_size = int(response.headers.get("Content-Length")) |
| 226 | + try: |
| 227 | + existing_size = os.path.getsize(result_path) |
| 228 | + except OSError: |
| 229 | + existing_size = 0 |
| 230 | + if linked_etag and total_size == existing_size: |
| 231 | + with builtins.open(result_path, "rb") as file: |
| 232 | + sha256_hash = hashlib.sha256() |
| 233 | + for byte_block in iter(lambda: file.read(4096), b""): |
| 234 | + sha256_hash.update(byte_block) |
| 235 | + if f'"{sha256_hash.hexdigest()}"' == linked_etag: |
| 236 | + nc.set_init_status(min(current_progress + progress_for_task, 99)) |
| 237 | + return result_path |
| 238 | + |
| 239 | + try: |
| 240 | + with builtins.open(tmp_path, "wb") as file: |
| 241 | + last_progress = current_progress |
| 242 | + for chunk in response.iter_raw(-1): |
| 243 | + downloaded_size += file.write(chunk) |
| 244 | + if total_size: |
| 245 | + new_progress = min( |
| 246 | + current_progress + int(progress_for_task * downloaded_size / total_size), 99 |
| 247 | + ) |
| 248 | + if new_progress != last_progress: |
| 249 | + nc.set_init_status(new_progress) |
| 250 | + last_progress = new_progress |
| 251 | + os.replace(tmp_path, result_path) |
| 252 | + except BaseException: |
| 253 | + if os.path.exists(tmp_path): |
| 254 | + os.remove(tmp_path) |
| 255 | + raise |
| 256 | + except FileLockTimeout as exc: |
| 257 | + raise ModelFetchError( |
| 258 | + f"Timed out waiting for lock on '{result_path}' after 7200s — another process may be stuck downloading" |
| 259 | + ) from exc |
252 | 260 |
|
253 | 261 | return result_path |
254 | 262 |
|
|
0 commit comments