Commit Graph
3 Commits
Author SHA1 Message Date
stumpylog 5bcde3205f Fix: move document files once per request, after its writes commit
A tag PATCH moved files from inside the tags.set() transaction while holding the document row lock. A concurrent save holding media.lock and waiting on that row deadlocked with it, and every later save on the instance queued behind media.lock until the webserver restarted.

FileMoveMiddleware opens a file move scope around every request, in sync or async mode, so each changed document is moved once after the view returns and never while a transaction holds row locks.
2026-11-03 15:09:29 -08:00
stumpylog 8f873604d3 Fix: collect document file moves per scope and move once on exit
Each save of a document moved its files on the spot, so one logical change could move them several times, and moves could run inside another open transaction.

defer_file_moves() opens a ContextVar-backed scope. Inside it, move requests are recorded and the outermost scope moves each document once on exit, or on commit if a transaction is still open. A failing move is logged and does not stop the others. Outside any scope moves stay immediate.
2026-11-03 15:09:29 -08:00
stumpylog 9a2b878859 Fix: extract document file moves out of the signal receiver
The file move receiver refreshed the caller's own instance from the database, which wiped unsaved in-memory changes. It ran on every m2m_changed action including pre_add and pre_remove, wrote modified even when nothing moved, and its no-move branch skipped trashed documents.

The move body now lives in documents.file_moves.move_files_for_document. It skips documents without a filename before taking media.lock, then takes the lock with a 300 second timeout, loads a fresh instance by pk, writes only when a filename column changes, and returns the instance. The receiver ignores reverse and pre_* m2m actions and copies just the final filename columns back onto the caller's instance.
2026-11-03 15:09:29 -08:00