mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-21 10:15:04 +02:00
fix(queue): claim a queue item before dispatch so it can't be reassigned mid-upload (#2615)
A queue row stays status='pending' for the whole FTP upload; status only flips to 'printing' at the end. The edit routes only blocked non-pending rows, so a PATCH during the upload window was accepted while the in-flight dispatch kept using its snapshotted printer -- splitting the queue row from the archive / expected-print / physical command across two printers, and enabling a duplicate dispatch on restart. The #1853 CAS guards cancellation, not reassignment. Add a dispatching_at claim, stamped atomically (WHERE status='pending' AND dispatching_at IS NULL) before any slow I/O and cleared on every exit. While held, the single-item PATCH returns 409 (re-checked just before the write), bulk edits skip the row, and the scheduler won't re-select it. Startup reconciliation clears claims orphaned by a crash mid-dispatch. The row stays pending throughout, so no status/UI/completion/reconciliation path changes. New column print_queue.dispatching_at (nullable, dialect-safe DDL). Covered by scheduler tests (claim exclusivity, non-pending rejection, release-on-exit, skip-already-claimed, startup stale-clear) and API tests (reassign 409, printer_id unchanged, bulk skip, unclaimed row still edits).
This commit is contained in:
@@ -1521,6 +1521,22 @@ async def run_migrations(conn):
|
||||
except (OperationalError, ProgrammingError):
|
||||
pass # Already applied
|
||||
|
||||
# Migration: Add dispatching_at claim column to print_queue (#2615). Nullable
|
||||
# timestamp; the type differs by dialect (SQLite DATETIME vs Postgres
|
||||
# TIMESTAMP) so an existing-DB upgrade doesn't hit "type datetime does not
|
||||
# exist" on Postgres. On a fresh DB create_all() already built the column, so
|
||||
# the ALTER is swallowed as "already exists".
|
||||
#
|
||||
# Placed AFTER the print_queue_new2 table-recreate above: that recreate
|
||||
# (SQLite-only, and only on ancient DBs whose archive_id is still NOT NULL)
|
||||
# rebuilds print_queue from an explicit column list that doesn't carry this
|
||||
# column, so adding it earlier would let the recreate silently drop it. Adding
|
||||
# it here means it survives that path.
|
||||
if is_sqlite():
|
||||
await _safe_execute(conn, "ALTER TABLE print_queue ADD COLUMN dispatching_at DATETIME")
|
||||
else:
|
||||
await _safe_execute(conn, "ALTER TABLE print_queue ADD COLUMN dispatching_at TIMESTAMP")
|
||||
|
||||
# Migration: Add HA energy sensor entity columns to smart_plugs
|
||||
await _safe_execute(conn, "ALTER TABLE smart_plugs ADD COLUMN ha_power_entity VARCHAR(100)")
|
||||
await _safe_execute(conn, "ALTER TABLE smart_plugs ADD COLUMN ha_energy_today_entity VARCHAR(100)")
|
||||
|
||||
Reference in New Issue
Block a user