a) _jobs waechst unbegrenzt — server.py:241,289,310
Jobs werden nur bei erfolgreichem Status-Poll nach Completion via del _jobs[job_id] geloescht. Wenn Client abbricht, bleiben sie fuer immer.
b) Race /export/download vs _cleanup_zips — server.py:366-381, server.py:478-497
Cleanup-Thread kann ZIP zwischen _zip_store.get(zip_id) und open(zip_path, "rb") loeschen. finally: os.unlink(zip_path) loescht ausserdem bei jeder Client-Disconnection -> kein Retry moeglich.
Fix
a) TTL-Cleanup-Thread analog _cleanup_zips, der _jobs mit created_at aelter als z.B. 1h purged.
b) Reference-Count im ZIP-Store: solange refs > 0, kein Cleanup. Bei Disconnect ZIP nicht im finally loeschen.
## Probleme
**a) `_jobs` waechst unbegrenzt** — `server.py:241,289,310`
Jobs werden nur bei erfolgreichem Status-Poll nach Completion via `del _jobs[job_id]` geloescht. Wenn Client abbricht, bleiben sie fuer immer.
**b) Race `/export/download` vs `_cleanup_zips`** — `server.py:366-381`, `server.py:478-497`
Cleanup-Thread kann ZIP zwischen `_zip_store.get(zip_id)` und `open(zip_path, "rb")` loeschen. `finally: os.unlink(zip_path)` loescht ausserdem bei jeder Client-Disconnection -> kein Retry moeglich.
## Fix
**a)** TTL-Cleanup-Thread analog `_cleanup_zips`, der `_jobs` mit `created_at` aelter als z.B. 1h purged.
**b)** Reference-Count im ZIP-Store: solange `refs > 0`, kein Cleanup. Bei Disconnect ZIP nicht im `finally` loeschen.
Job-Dict bekommt jetzt created_at beim Anlegen (/analyze, /export)
Background-Thread _cleanup_jobs purged Jobs aelter als _JOB_TTL = 3600s
Abandoned Jobs werden so nicht mehr ewig im RAM gehalten
(b) ZIP-Race + Disconnect-Loss
_zip_store[id] hat jetzt refs-Zaehler
/export/download inkrementiert refs vor Stream-Start, dekrementiert im finally
_cleanup_zips ueberspringt Eintraege mit refs > 0
os.unlink im Stream-finally entfernt - ZIP bleibt verfuegbar fuer Retry
Manueller Test: ZIP mit ID X einmal herunterladen -> 200 + 1094B. Direkt danach erneut mit gleicher ID -> 200 + 1094B. Vorher: 2. Versuch waere 404 gewesen, weil das finally die Datei geloescht hat.
Fix umgesetzt in `server.py`:
**(a) Jobs-TTL**
- Job-Dict bekommt jetzt `created_at` beim Anlegen (`/analyze`, `/export`)
- Background-Thread `_cleanup_jobs` purged Jobs aelter als `_JOB_TTL = 3600s`
- Abandoned Jobs werden so nicht mehr ewig im RAM gehalten
**(b) ZIP-Race + Disconnect-Loss**
- `_zip_store[id]` hat jetzt `refs`-Zaehler
- `/export/download` inkrementiert `refs` vor Stream-Start, dekrementiert im `finally`
- `_cleanup_zips` ueberspringt Eintraege mit `refs > 0`
- `os.unlink` im Stream-finally entfernt - ZIP bleibt verfuegbar fuer Retry
Manueller Test: ZIP mit ID X einmal herunterladen -> 200 + 1094B. Direkt danach erneut mit gleicher ID -> 200 + 1094B. Vorher: 2. Versuch waere 404 gewesen, weil das `finally` die Datei geloescht hat.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Probleme
a)
_jobswaechst unbegrenzt —server.py:241,289,310Jobs werden nur bei erfolgreichem Status-Poll nach Completion via
del _jobs[job_id]geloescht. Wenn Client abbricht, bleiben sie fuer immer.b) Race
/export/downloadvs_cleanup_zips—server.py:366-381,server.py:478-497Cleanup-Thread kann ZIP zwischen
_zip_store.get(zip_id)undopen(zip_path, "rb")loeschen.finally: os.unlink(zip_path)loescht ausserdem bei jeder Client-Disconnection -> kein Retry moeglich.Fix
a) TTL-Cleanup-Thread analog
_cleanup_zips, der_jobsmitcreated_ataelter als z.B. 1h purged.b) Reference-Count im ZIP-Store: solange
refs > 0, kein Cleanup. Bei Disconnect ZIP nicht imfinallyloeschen.Fix umgesetzt in
server.py:(a) Jobs-TTL
created_atbeim Anlegen (/analyze,/export)_cleanup_jobspurged Jobs aelter als_JOB_TTL = 3600s(b) ZIP-Race + Disconnect-Loss
_zip_store[id]hat jetztrefs-Zaehler/export/downloadinkrementiertrefsvor Stream-Start, dekrementiert imfinally_cleanup_zipsueberspringt Eintraege mitrefs > 0os.unlinkim Stream-finally entfernt - ZIP bleibt verfuegbar fuer RetryManueller Test: ZIP mit ID X einmal herunterladen -> 200 + 1094B. Direkt danach erneut mit gleicher ID -> 200 + 1094B. Vorher: 2. Versuch waere 404 gewesen, weil das
finallydie Datei geloescht hat.