From 936f9363a0bccc056206d1f1a934ea36c1d3bc24 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Mon, 2 Nov 2026 07:59:27 -0800 Subject: [PATCH] Fix: ensure import bulk_edit tasks in Celery workers (#14653) --- src/paperless/settings/__init__.py | 3 +++ src/paperless/tests/test_celery.py | 39 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/paperless/settings/__init__.py b/src/paperless/settings/__init__.py index b3e2b71ab2..62188336d1 100644 --- a/src/paperless/settings/__init__.py +++ b/src/paperless/settings/__init__.py @@ -690,6 +690,9 @@ logging.config.dictConfig(LOGGING) # https://docs.celeryq.dev/en/stable/userguide/configuration.html +# Tasks outside tasks.py must be loaded even when Django skips checks +CELERY_IMPORTS = ("documents.bulk_edit",) + CELERY_BROKER_URL = _CELERY_REDIS_URL CELERY_RESULT_BACKEND = _CELERY_REDIS_URL CELERY_RESULT_SERIALIZER = "signed-pickle" diff --git a/src/paperless/tests/test_celery.py b/src/paperless/tests/test_celery.py index 83a2e9a84a..56ecf57484 100644 --- a/src/paperless/tests/test_celery.py +++ b/src/paperless/tests/test_celery.py @@ -1,5 +1,8 @@ import hmac +import os import pickle +import subprocess +import sys from hashlib import sha256 from pathlib import Path @@ -11,6 +14,42 @@ from paperless.celery import signed_pickle_loads from paperless.signed_pickle import HMAC_SIZE +def test_tasks_registered_without_system_checks() -> None: + # Use a fresh interpreter: Django checks and other tests can import views, + # hiding tasks that the worker would otherwise never register. + result = subprocess.run( + [ + sys.executable, + "-c", + """ +import sys + +from paperless.celery import app + +app.loader.import_default_modules() +expected = { + "documents.bulk_edit.delete", + "documents.bulk_edit.restore_archive_serial_numbers_task", + "documents.signals.handlers.process_cf_select_update", + "documents.workflows.webhooks.send_webhook", + "paperless_mail.mail.apply_mail_action", + "paperless_mail.mail.error_callback", +} +missing = expected - set(app.tasks) +assert not missing, f"Unregistered tasks: {sorted(missing)}" +assert "paperless.urls" not in sys.modules +""", + ], + env={**os.environ, "CELERY_SKIP_CHECKS": "1"}, + cwd=Path(__file__).resolve().parents[2], + capture_output=True, + text=True, + timeout=60, + check=False, + ) + assert result.returncode == 0, result.stdout + result.stderr + + class TestSignedPickleSerializer: def test_roundtrip_simple_types(self) -> None: """Signed pickle can round-trip basic JSON-like types."""