Skip to content

Commit c2f4ad3

Browse files
Copilotlstein
andauthored
Fix race condition in download queue when concurrent jobs share destination directory (#104)
* Initial plan * Fix race condition in _do_download when scanning for .downloading files Co-authored-by: lstein <111189+lstein@users.noreply.github.com> * chore(backend): update copyright --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: lstein <111189+lstein@users.noreply.github.com> Co-authored-by: Lincoln Stein <lincoln.stein@gmail.com>
1 parent 4fd5cd2 commit c2f4ad3

1 file changed

Lines changed: 18 additions & 13 deletions

File tree

invokeai/app/services/download/download_default.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2023, Lincoln D. Stein
1+
# Copyright (c) 2023,2026 Lincoln D. Stein
22
"""Implementation of multithreaded download queue for invokeai."""
33

44
import os
@@ -388,18 +388,23 @@ def _do_download(self, job: DownloadJob) -> None:
388388
if len(candidates) == 1:
389389
inferred = candidates[0].with_name(candidates[0].name.removesuffix(".downloading"))
390390
job.download_path = inferred
391-
resume_from = candidates[0].stat().st_size
392-
job.bytes = resume_from
393-
self._logger.debug(
394-
f"Resume check (dir): inferred in-progress file path={candidates[0]} size={resume_from} bytes"
395-
)
396-
if resume_from > 0:
397-
if job.etag:
398-
header["If-Range"] = job.etag
399-
elif job.last_modified:
400-
header["If-Range"] = job.last_modified
401-
header["Range"] = f"bytes={resume_from}-"
402-
open_mode = "ab"
391+
try:
392+
resume_from = candidates[0].stat().st_size
393+
except FileNotFoundError:
394+
# The .downloading file was renamed/deleted between glob and stat (race condition); skip resume.
395+
job.download_path = None
396+
else:
397+
job.bytes = resume_from
398+
self._logger.debug(
399+
f"Resume check (dir): inferred in-progress file path={candidates[0]} size={resume_from} bytes"
400+
)
401+
if resume_from > 0:
402+
if job.etag:
403+
header["If-Range"] = job.etag
404+
elif job.last_modified:
405+
header["If-Range"] = job.last_modified
406+
header["Range"] = f"bytes={resume_from}-"
407+
open_mode = "ab"
403408
else:
404409
self._logger.debug(
405410
"Resume check (dir): no prior download_path available; cannot resume from disk "

0 commit comments

Comments
 (0)