Fix: don't re-queue a consume-folder file that is already queued and awaiting consumption (#13526)

This commit is contained in:
Trenton H
2026-08-03 09:55:12 -07:00
committed by GitHub
parent cfa1d3b058
commit 23c11f49d0
2 changed files with 47 additions and 0 deletions
@@ -632,8 +632,20 @@ class Command(BaseCommand):
# Process each change
for change_type, path in changes:
path = Path(path).resolve()
if change_type == Change.deleted:
# Consumed (or otherwise removed); a later file
# reusing this name must not be skipped as
# already-queued.
queued.discard(path)
if not path.is_file():
continue
if path in queued:
# Already queued and awaiting consumption; a stray
# event (NAS metadata touch, AV scan, etc.) while
# the file sits on disk mid-consumption must not
# cause it to be queued a second time (GH #13511).
logger.debug(f"Ignoring event for queued file: {path}")
continue
logger.debug(f"Event: {change_type.name} for {path}")
tracker.track(path, change_type)
@@ -880,6 +880,41 @@ class TestCommandWatch:
]
assert call_args.original_file.name == "valid.pdf"
def test_ignores_event_for_already_queued_file(
self,
consumption_dir: Path,
sample_pdf: Path,
mock_consume_file_delay: MagicMock,
start_consumer: Callable[..., ConsumerThread],
) -> None:
"""
A stray filesystem event (NAS metadata touch, AV scan, etc.) on a
file that has already been queued and is awaiting consumption must
not cause it to be queued a second time (GH #13511). The task is
mocked, so the file is never removed from disk, mirroring a
long-running OCR job still holding it.
"""
thread = start_consumer()
target = consumption_dir / "document.pdf"
shutil.copy(sample_pdf, target)
wait_for_mock_call(mock_consume_file_delay.apply_async, timeout_s=2.0)
if thread.exception:
raise thread.exception
assert mock_consume_file_delay.apply_async.call_count == 1
# Simulate a stray event on the still-present, already-queued file.
target.touch()
sleep(0.5)
if thread.exception:
raise thread.exception
assert mock_consume_file_delay.apply_async.call_count == 1
@pytest.mark.django_db
@pytest.mark.usefixtures("mock_supported_extensions")
def test_stop_flag_stops_consumer(