mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 11:12:35 +02:00
Symptom: user queued a batch of 10 prints, pressed Cancel on a pending row, the print started anyway. Repeated consecutively. Support bundle also showed 15x "sqlite3.OperationalError: database is locked" from the sensor history recorder in the same 8-minute window. Root cause is a check-then-act race in _start_print. check_queue takes a snapshot of pending items, then _start_print does FTP delete + FTP upload (5-30s) before the unconditional item.status = "printing"; db.commit() at line 2792. /cancel commits status='cancelled' in a separate session during that window; the scheduler's stale in-memory write overwrites it and start_print ships. The lock-contention finding is the same shape from a different angle: _start_print did await db.flush() at line 2555 (after item.archive_id set + library_file delete) which opens the SQLite WAL writer lock and holds it through the FTP upload, queueing every concurrent writer behind it including the user's own cancel commit. Three guards layered: 1) Atomic CAS at the pending->printing transition. UPDATE print_queue SET status='printing', started_at=NOW() WHERE id=:id AND status='pending'. rowcount==0 means user won; log abort, best-effort delete_file_async the file we just FTP'd up so it doesn't leak into the printer's BambuStudio file picker, send queue_item_failed WS event with reason="cancelled_mid_dispatch", return without calling printer_manager.start_print. 2) Early db.refresh(item) + bail right after the printer connectivity check. Saves the wasted FTP upload when the row was already cancelled before _start_print resumed. Defense in depth; guard 1 catches the same case at the CAS point. 3) flush -> commit before the FTP block. The library-file-to-archive promotion's writes commit cleanly, WAL writer lock releases, sensor history and concurrent cancels stop queueing behind the scheduler. The flush-not-commit pattern was rolling back a pointer to an already-committed archive row, so the new behaviour matches reality (archive committed, pointer committed, FTP unblocked).