From 58392bf7a6a6d9c0112aa334bf62dc6aa7c87d14 Mon Sep 17 00:00:00 2001 From: Talmaj Marinc Date: Tue, 30 Jun 2026 10:20:54 +0200 Subject: [PATCH] Truncate file to 0 before restarting. --- app/model_downloader/engine/job.py | 6 +++++- app/model_downloader/engine/writer.py | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/model_downloader/engine/job.py b/app/model_downloader/engine/job.py index ad05192b2..942558678 100644 --- a/app/model_downloader/engine/job.py +++ b/app/model_downloader/engine/job.py @@ -361,9 +361,13 @@ class DownloadJob: "GET", self.spec.url, credential_id=self.spec.credential_id, headers=headers ) as (resp, _final): if offset > 0 and resp.status == 200: - # Resume not honoured -> start over from the beginning. + # Resume not honoured -> start over from the beginning. Truncate + # the existing partial so stale trailing bytes from the prior + # attempt cannot survive past the new (possibly shorter) end. offset = 0 seg.bytes_done = 0 + self.state.bytes_done = 0 + await self._writer.truncate(0) elif offset > 0 and resp.status != 206: self._raise_for_status(resp.status) elif offset == 0 and resp.status != 200: diff --git a/app/model_downloader/engine/writer.py b/app/model_downloader/engine/writer.py index ada676475..3b69c20b2 100644 --- a/app/model_downloader/engine/writer.py +++ b/app/model_downloader/engine/writer.py @@ -43,6 +43,14 @@ class FileWriter: _EXECUTOR, os.ftruncate, self._fd, size ) + async def truncate(self, size: int = 0) -> None: + """Truncate the file to ``size`` bytes (default: empty it).""" + if self._fd is None: + return + await asyncio.get_running_loop().run_in_executor( + _EXECUTOR, os.ftruncate, self._fd, size + ) + async def write_at(self, offset: int, data: bytes) -> None: assert self._fd is not None, "writer not opened" await asyncio.get_running_loop().run_in_executor(