fix: Race Condition bei gleichzeitigen Downloads in savetv_web.py
- Thread-Lock fuer Progress-Datei: verhindert korruptes JSON bei vielen simultanen Downloads - start_new_session=True in Popen: wget-Prozesse ueberleben Service-Neustarts - Atomic load+modify+save Pattern via _load_progress_raw/_save_progress_raw
This commit is contained in:
parent
25642d6b62
commit
32da34b3c2
1 changed files with 31 additions and 13 deletions
|
|
@ -43,9 +43,11 @@ def _save_download_log(log):
|
|||
|
||||
DOWNLOAD_PROGRESS = Path("/mnt/savetv/.download_progress.json")
|
||||
DOWNLOAD_DIR = Path("/mnt/savetv")
|
||||
_PROGRESS_LOCK = threading.Lock()
|
||||
|
||||
|
||||
def _load_progress():
|
||||
def _load_progress_raw():
|
||||
"""Liest Progress-Datei ohne Lock (nur innerhalb von _PROGRESS_LOCK aufrufen)."""
|
||||
if DOWNLOAD_PROGRESS.exists():
|
||||
try:
|
||||
return json.loads(DOWNLOAD_PROGRESS.read_text())
|
||||
|
|
@ -54,11 +56,22 @@ def _load_progress():
|
|||
return {}
|
||||
|
||||
|
||||
def _save_progress_raw(prog):
|
||||
"""Schreibt Progress-Datei ohne Lock (nur innerhalb von _PROGRESS_LOCK aufrufen)."""
|
||||
DOWNLOAD_PROGRESS.write_text(json.dumps(prog, ensure_ascii=False, indent=2))
|
||||
|
||||
|
||||
def _load_progress():
|
||||
with _PROGRESS_LOCK:
|
||||
return _load_progress_raw()
|
||||
|
||||
|
||||
def _save_progress(prog):
|
||||
try:
|
||||
DOWNLOAD_PROGRESS.write_text(json.dumps(prog, ensure_ascii=False, indent=2))
|
||||
except Exception:
|
||||
pass
|
||||
with _PROGRESS_LOCK:
|
||||
try:
|
||||
_save_progress_raw(prog)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def _head_content_length(url):
|
||||
|
|
@ -722,12 +735,14 @@ def api_download():
|
|||
filename = f"{safe_title}_{tid}.mp4"
|
||||
target = DOWNLOAD_DIR / filename
|
||||
|
||||
progress[str(tid)] = {
|
||||
"filename": filename,
|
||||
"expected_bytes": expected_bytes,
|
||||
"started_at": datetime.now().isoformat(),
|
||||
}
|
||||
_save_progress(progress)
|
||||
with _PROGRESS_LOCK:
|
||||
cur_progress = _load_progress_raw()
|
||||
cur_progress[str(tid)] = {
|
||||
"filename": filename,
|
||||
"expected_bytes": expected_bytes,
|
||||
"started_at": datetime.now().isoformat(),
|
||||
}
|
||||
_save_progress_raw(cur_progress)
|
||||
|
||||
DOWNLOAD_DIR.mkdir(parents=True, exist_ok=True)
|
||||
try:
|
||||
|
|
@ -735,10 +750,13 @@ def api_download():
|
|||
["wget", "-q", "-O", str(target), url],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
start_new_session=True,
|
||||
)
|
||||
except Exception as e:
|
||||
progress.pop(str(tid), None)
|
||||
_save_progress(progress)
|
||||
with _PROGRESS_LOCK:
|
||||
cur_progress = _load_progress_raw()
|
||||
cur_progress.pop(str(tid), None)
|
||||
_save_progress_raw(cur_progress)
|
||||
return {"tid": tid, "ok": False, "error": f"wget: {e}"}
|
||||
|
||||
dl_log[str(tid)] = "running"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue