hms_notified.py 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. """Persistence for the HMS faults already notified (#3486).
  2. The notification de-duplication itself stays in ``main._take_new_hms_faults``,
  3. in memory. This only stores which fault keys it holds, so a restart does not
  4. send every fault a printer still lists again.
  5. """
  6. import asyncio
  7. import logging
  8. from sqlalchemy import delete, select
  9. from backend.app.core.database import async_session
  10. from backend.app.models.hms_notified_fault import HmsNotifiedFault
  11. logger = logging.getLogger(__name__)
  12. # One writer at a time per printer, so the last write is the latest set.
  13. _locks: dict[int, asyncio.Lock] = {}
  14. async def load_notified_hms_faults() -> dict[int, set[str]]:
  15. """Every printer's notified fault keys, as stored."""
  16. async with async_session() as db:
  17. rows = (await db.execute(select(HmsNotifiedFault.printer_id, HmsNotifiedFault.fault_key))).all()
  18. loaded: dict[int, set[str]] = {}
  19. for printer_id, fault_key in rows:
  20. loaded.setdefault(printer_id, set()).add(fault_key)
  21. return loaded
  22. async def save_notified_hms_faults(printer_id: int, current_keys) -> None:
  23. """Store *current_keys()* as the printer's notified faults.
  24. *current_keys* is called once the lock is held, so a write that waited
  25. stores the set as it is then, not as it was when the write was asked for.
  26. """
  27. lock = _locks.setdefault(printer_id, asyncio.Lock())
  28. async with lock:
  29. keys = set(current_keys())
  30. async with async_session() as db:
  31. stored = set(
  32. (
  33. await db.execute(
  34. select(HmsNotifiedFault.fault_key).where(HmsNotifiedFault.printer_id == printer_id)
  35. )
  36. ).scalars()
  37. )
  38. gone = stored - keys
  39. if gone:
  40. await db.execute(
  41. delete(HmsNotifiedFault).where(
  42. HmsNotifiedFault.printer_id == printer_id, HmsNotifiedFault.fault_key.in_(gone)
  43. )
  44. )
  45. for key in keys - stored:
  46. db.add(HmsNotifiedFault(printer_id=printer_id, fault_key=key))
  47. await db.commit()