From f51a78940f9947eb8139adb9acda615c131df184 Mon Sep 17 00:00:00 2001 From: Jo Date: Tue, 7 Jul 2026 13:38:59 +0200 Subject: [PATCH] fix: HA sync uses per-printer autocommit connections to prevent database locked --- app.py | 65 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/app.py b/app.py index 5ff68de..f76fba9 100644 --- a/app.py +++ b/app.py @@ -2040,46 +2040,49 @@ def _ha_sync_once(): states = _ha_fetch_all_states(ha_url, ha_token) if not states: return - # Ouvrir la connexion d'écriture APRÈS l'appel HTTP (qui peut être long) - conn = sqlite3.connect(DATABASE, timeout=30) - conn.row_factory = sqlite3.Row - conn.execute('PRAGMA journal_mode=WAL') - printers = conn.execute( + # Lire les imprimantes avec une connexion courte (lecture seule) + _rc = sqlite3.connect(DATABASE, timeout=15) + _rc.row_factory = sqlite3.Row + printers = _rc.execute( "SELECT id, name, ha_entity_prefix FROM printers " "WHERE ha_entity_prefix IS NOT NULL AND ha_entity_prefix != ''" ).fetchall() + _rc.close() + now_iso = datetime.now(timezone.utc).replace(tzinfo=None).isoformat() window = (datetime.now(timezone.utc).replace(tzinfo=None) + timedelta(minutes=30)).isoformat() for p in printers: prefix = p['ha_entity_prefix'] ha_status = states.get(f'sensor.{prefix}_etat_de_l_impression', 'unknown') ha_error = states.get(f'binary_sensor.{prefix}_erreur_d_impression', 'off') - slot = conn.execute( - "SELECT id, status FROM print_slots " - "WHERE printer_id=? AND status IN ('planned','running') " - "AND planned_start <= ? AND planned_end >= ? " - "ORDER BY planned_start DESC LIMIT 1", - (p['id'], window, now_iso) - ).fetchone() - if not slot: - continue - new_status = None - if ha_error == 'on': - new_status = 'failed' - elif ha_status == 'finish': - new_status = 'done' - elif ha_status == 'running' and slot['status'] == 'planned': - new_status = 'running' - if new_status: - conn.execute('UPDATE print_slots SET status=? WHERE id=?', - (new_status, slot['id'])) - if ha_ignored > 0: - conn.execute('UPDATE print_slots SET pieces_ignored=? WHERE id=?', - (ha_ignored, slot['id'])) - try: - conn.commit() - finally: - conn.close() + # Connexion courte par imprimante : on lit, on écrit, on commit, on ferme + wc = sqlite3.connect(DATABASE, timeout=15, isolation_level=None) + wc.row_factory = sqlite3.Row + try: + slot = wc.execute( + "SELECT id, status FROM print_slots " + "WHERE printer_id=? AND status IN ('planned','running') " + "AND planned_start <= ? AND planned_end >= ? " + "ORDER BY planned_start DESC LIMIT 1", + (p['id'], window, now_iso) + ).fetchone() + if not slot: + continue + new_status = None + if ha_error == 'on': + new_status = 'failed' + elif ha_status == 'finish': + new_status = 'done' + elif ha_status == 'running' and slot['status'] == 'planned': + new_status = 'running' + if new_status: + wc.execute('UPDATE print_slots SET status=? WHERE id=?', + (new_status, slot['id'])) + if ha_ignored > 0: + wc.execute('UPDATE print_slots SET pieces_ignored=? WHERE id=?', + (ha_ignored, slot['id'])) + finally: + wc.close() except Exception as e: print(f'[HA sync] {e}')