feat(import): T16 job purjare + purge_after SET la sent (OV-5)
- mark(sent): seteaza purge_after = now + 90 zile (GDPR/L.142) - purge_expired(conn): sterge submissions sent expirate + import_batches expirate (import_rows via ON DELETE CASCADE). NULL purge_after = nu expira. - run(): tick de purjare odata pe ora (guard _last_purge_time + _PURGE_INTERVAL_S) NU mai agresiv, nu blocheaza trimiterea - 8 teste: purge_after la sent, alte stari fara purge, expirati vs neexpirat, queued neatins, cascade import_rows, null purge_after pastrat Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -75,11 +75,43 @@ def _is_transient(exc: Exception) -> bool:
|
||||
# --- Operatii pe submissions ---
|
||||
|
||||
def mark(conn, submission_id: int, status: str, *, rar_status_code=None, rar_error=None, id_prezentare=None) -> None:
|
||||
conn.execute(
|
||||
"UPDATE submissions SET status=?, rar_status_code=?, rar_error=?, id_prezentare=?, "
|
||||
"sending_since=NULL, updated_at=datetime('now') WHERE id=?",
|
||||
(status, rar_status_code, rar_error, id_prezentare, submission_id),
|
||||
if status == "sent":
|
||||
# T16: purge_after = sent + 90 zile (GDPR/L.142 retentie maxima).
|
||||
conn.execute(
|
||||
"UPDATE submissions SET status=?, rar_status_code=?, rar_error=?, id_prezentare=?, "
|
||||
"sending_since=NULL, updated_at=datetime('now'), "
|
||||
"purge_after=datetime('now', '+90 days') WHERE id=?",
|
||||
(status, rar_status_code, rar_error, id_prezentare, submission_id),
|
||||
)
|
||||
else:
|
||||
conn.execute(
|
||||
"UPDATE submissions SET status=?, rar_status_code=?, rar_error=?, id_prezentare=?, "
|
||||
"sending_since=NULL, updated_at=datetime('now') WHERE id=?",
|
||||
(status, rar_status_code, rar_error, id_prezentare, submission_id),
|
||||
)
|
||||
|
||||
|
||||
# T16: purge interval in secunde (odata pe ora, nu prea agresiv)
|
||||
_PURGE_INTERVAL_S = 3600
|
||||
|
||||
|
||||
def purge_expired(conn) -> dict[str, int]:
|
||||
"""Sterge randurile expirate (purge_after < now).
|
||||
|
||||
T16/OV-5: purge_after era exportat dar setat de nimeni si niciun job nu exista.
|
||||
Acum: submissions sent + expirate, import_batches expirate (import_rows via CASCADE).
|
||||
Intoarce {submissions_purged, batches_purged}.
|
||||
"""
|
||||
cur_sub = conn.execute(
|
||||
"DELETE FROM submissions WHERE purge_after IS NOT NULL AND purge_after < datetime('now') AND status='sent'"
|
||||
)
|
||||
cur_batch = conn.execute(
|
||||
"DELETE FROM import_batches WHERE purge_after IS NOT NULL AND purge_after < datetime('now')"
|
||||
)
|
||||
return {
|
||||
"submissions_purged": cur_sub.rowcount,
|
||||
"batches_purged": cur_batch.rowcount,
|
||||
}
|
||||
|
||||
|
||||
def requeue_with_backoff(conn, settings: Settings, submission_id: int, *, reason: str) -> None:
|
||||
@@ -330,11 +362,24 @@ def run() -> int:
|
||||
print(f"[worker] pornit (send_enabled={settings.worker_send_enabled}, env={settings.rar_env})", flush=True)
|
||||
|
||||
sessions = AccountSessions(settings)
|
||||
_last_purge_time: float = 0.0
|
||||
|
||||
while _running:
|
||||
try:
|
||||
write_heartbeat(conn, detail=f"poll (queue={_queue_depth(conn)})")
|
||||
|
||||
# T16: purjare periodica (odata pe ora) — NU mai frecvent.
|
||||
now_ts = time.time()
|
||||
if now_ts - _last_purge_time >= _PURGE_INTERVAL_S:
|
||||
stats = purge_expired(conn)
|
||||
if stats["submissions_purged"] or stats["batches_purged"]:
|
||||
print(
|
||||
f"[worker] purjare: {stats['submissions_purged']} submissions, "
|
||||
f"{stats['batches_purged']} batches sterse",
|
||||
flush=True,
|
||||
)
|
||||
_last_purge_time = now_ts
|
||||
|
||||
if not settings.worker_send_enabled:
|
||||
time.sleep(settings.worker_poll_interval_s)
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user