🐛(backend) correctly configure celery beat to run wopi configuration

The celery beat configuration was not working correctly, we installed
the database scheduler but we didn't configure it correctly. We prefer
removing this scheduler to use the default one. Instead, the crontab
part can be configured using environment variable. By default it will be
run every night at 3AM.
This commit is contained in:
Manuel Raynaud
2026-01-27 17:23:27 +01:00
parent 82cf211b88
commit 46d61a9c76
8 changed files with 42 additions and 46 deletions

View File

@@ -31,6 +31,7 @@ db.sqlite3
.mypy_cache
.pylint.d
.pytest_cache
**/celerybeat-schedule*
# Frontend
node_modules

1
.gitignore vendored
View File

@@ -28,6 +28,7 @@ share/python-wheels/
MANIFEST
.DS_Store
.next/
celerybeat-schedule*
# Translations # Translations
*.mo

View File

@@ -16,10 +16,15 @@ and this project adheres to
- 🔥(backend) remove usage of atomic transaction for item creation
### Fixed
- 🐛(backend) correctly configure celery beat to run wopi configuration
### Security
- 🔒️(backend) prevent mismatch mimetype between object storage and application
## [v0.11.1] - 2026-01-13
### Fixed

View File

@@ -108,3 +108,15 @@ This document lists all configurable environment variables for the Drive applica
| `SPECTACULAR_SETTINGS_ENABLE_DJANGO_DEPLOY_CHECK` | Enable Django deploy check in Spectacular | `False` |
| `STORAGES_STATICFILES_BACKEND` | Backend for static files storage | `whitenoise.storage.CompressedManifestStaticFilesStorage` |
| `TRASHBIN_CUTOFF_DAYS` | Number of days before items are permanently deleted from trash | `30` |
| `WOPI_CLIENTS` | List of client name. These client names will be used in the post_setup | [] |
| `WOPI_{CLIENT_NAME}_DISCOVERY_URL` | The discovery url for each client present in the `WOPI_CLIENTS`. if `WOPI_CLIENTS=vendorA` then set `WOPI_VENDORA_DISCOVERY_URL` | |
| `WOPI_EXCLUDED_MIMETYPES` | List of mimetypes excluded when parsing the discovery url | See settings.py module |
| `WOPI_EXCLUDED_EXTENSIONS` | List of extensions excluded when parsing the discovery url | See settings.py module |
| `WOPI_SRC_BASE_URL` | The backend url | None |
| `WOPI_ACCESS_TOKEN_TIMEOUT` | TTL in seconds for the access_token_ttl sent to the WOPI client | `36000` (10H) |
| `WOPI_LOCK_TIMEOUT` | TTL for the lock acquired by a WOPI client | `1800` (30 min) |
| `WOPI_DISABLE_CHAT` | Disable chat in the WOPI client interface | `0` |
| `WOPI_CONFIGURATION_CRONTAB_MINUTE` | Used to configure the celery beat crontab, See https://docs.celeryq.dev/en/main/reference/celery.schedules.html#celery.schedules.crontab | `0` |
| `WOPI_CONFIGURATION_CRONTAB_HOUR` | Used to configure the celery beat crontab, See https://docs.celeryq.dev/en/main/reference/celery.schedules.html#celery.schedules.crontab | `3` |
| `WOPI_CONFIGURATION_CRONTAB_DAY_OF_MONTH` | Used to configure the celery beat crontab, See https://docs.celeryq.dev/en/main/reference/celery.schedules.html#celery.schedules.crontab | `*` |
| `WOPI_CONFIGURATION_CRONTAB_MONTH_OF_YEAR` | Used to configure the celery beat crontab, See https://docs.celeryq.dev/en/main/reference/celery.schedules.html#celery.schedules.crontab | `*` |

View File

@@ -833,7 +833,6 @@ class Base(Configuration):
"drf_standardized_errors",
# Third party apps
"corsheaders",
"django_celery_beat",
"django_filters",
"dockerflow.django",
"rest_framework",
@@ -1049,7 +1048,6 @@ class Base(Configuration):
# Celery
CELERY_BROKER_URL = values.Value("redis://redis:6379/0")
CELERY_BROKER_TRANSPORT_OPTIONS = values.DictValue({})
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"
# Session
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
@@ -1391,6 +1389,21 @@ class Base(Configuration):
0, environ_name="WOPI_DISABLE_CHAT", environ_prefix=None
)
WOPI_CONFIGURATION_CRONTAB_MINUTE = values.Value(
0, environ_name="WOPI_CONFIGURATION_CRONTAB_MINUTE", environ_prefix=None
)
WOPI_CONFIGURATION_CRONTAB_HOUR = values.Value(
3, environ_name="WOPI_CONFIGURATION_CRONTAB_HOUR", environ_prefix=None
)
WOPI_CONFIGURATION_CRONTAB_DAY_OF_MONTH = values.Value(
"*", environ_name="WOPI_CONFIGURATION_CRONTAB_DAY_OF_MONTH", environ_prefix=None
)
WOPI_CONFIGURATION_CRONTAB_MONTH_OF_YEAR = values.Value(
"*",
environ_name="WOPI_CONFIGURATION_CRONTAB_MONTH_OF_YEAR",
environ_prefix=None,
)
# Malware detection
MALWARE_DETECTION = {
"BACKEND": values.Value(

View File

@@ -30,7 +30,6 @@ dependencies = [
"celery[redis]==5.6.2",
"defusedxml==0.7.1",
"django<6.0.0",
"django-celery-beat==2.8.1",
"django-configurations==2.5.1",
"django-cors-headers==4.9.0",
"django-countries==8.2.0",

40
src/backend/uv.lock generated
View File

@@ -289,18 +289,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ce/a3/43b749004e3c09452e39bb56347a008f0a0668aad37324a99b5c8ca91d9e/coverage-7.12.0-py3-none-any.whl", hash = "sha256:159d50c0b12e060b15ed3d39f87ed43d4f7f7ad40b8a534f4dd331adbb51104a", size = 209503, upload-time = "2025-11-18T13:34:18.892Z" },
]
[[package]]
name = "cron-descriptor"
version = "2.0.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7c/31/0b21d1599656b2ffa6043e51ca01041cd1c0f6dacf5a3e2b620ed120e7d8/cron_descriptor-2.0.6.tar.gz", hash = "sha256:e39d2848e1d8913cfb6e3452e701b5eec662ee18bea8cc5aa53ee1a7bb217157", size = 49456, upload-time = "2025-09-03T16:30:22.434Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/21/cc/361326a54ad92e2e12845ad15e335a4e14b8953665007fb514d3393dfb0f/cron_descriptor-2.0.6-py3-none-any.whl", hash = "sha256:3a1c0d837c0e5a32e415f821b36cf758eb92d510e6beff8fbfe4fa16573d93d6", size = 74446, upload-time = "2025-09-03T16:30:21.397Z" },
]
[[package]]
name = "cryptography"
version = "46.0.3"
@@ -404,23 +392,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/17/b0/7f42bfc38b8f19b78546d47147e083ed06e12fc29c42da95655e0962c6c2/django-5.2.9-py3-none-any.whl", hash = "sha256:3a4ea88a70370557ab1930b332fd2887a9f48654261cdffda663fef5976bb00a", size = 8290652, upload-time = "2025-12-02T14:01:03.485Z" },
]
[[package]]
name = "django-celery-beat"
version = "2.8.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "celery" },
{ name = "cron-descriptor" },
{ name = "django" },
{ name = "django-timezone-field" },
{ name = "python-crontab" },
{ name = "tzdata" },
]
sdist = { url = "https://files.pythonhosted.org/packages/aa/11/0c8b412869b4fda72828572068312b10aafe7ccef7b41af3633af31f9d4b/django_celery_beat-2.8.1.tar.gz", hash = "sha256:dfad0201c0ac50c91a34700ef8fa0a10ee098cc7f3375fe5debed79f2204f80a", size = 175802, upload-time = "2025-05-13T06:58:29.246Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/61/e5/3a0167044773dee989b498e9a851fc1663bea9ab879f1179f7b8a827ac10/django_celery_beat-2.8.1-py3-none-any.whl", hash = "sha256:da2b1c6939495c05a551717509d6e3b79444e114a027f7b77bf3727c2a39d171", size = 104833, upload-time = "2025-05-13T06:58:27.309Z" },
]
[[package]]
name = "django-configurations"
version = "2.5.1"
@@ -669,7 +640,6 @@ dependencies = [
{ name = "defusedxml" },
{ name = "dj-database-url" },
{ name = "django" },
{ name = "django-celery-beat" },
{ name = "django-configurations" },
{ name = "django-cors-headers" },
{ name = "django-countries" },
@@ -732,7 +702,6 @@ requires-dist = [
{ name = "defusedxml", specifier = "==0.7.1" },
{ name = "dj-database-url", specifier = "==3.0.1" },
{ name = "django", specifier = "<6.0.0" },
{ name = "django-celery-beat", specifier = "==2.8.1" },
{ name = "django-configurations", specifier = "==2.5.1" },
{ name = "django-cors-headers", specifier = "==4.9.0" },
{ name = "django-countries", specifier = "==8.2.0" },
@@ -1416,15 +1385,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" },
]
[[package]]
name = "python-crontab"
version = "3.3.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/99/7f/c54fb7e70b59844526aa4ae321e927a167678660ab51dda979955eafb89a/python_crontab-3.3.0.tar.gz", hash = "sha256:007c8aee68dddf3e04ec4dce0fac124b93bd68be7470fc95d2a9617a15de291b", size = 57626, upload-time = "2025-07-13T20:05:35.535Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/47/42/bb4afa5b088f64092036221843fc989b7db9d9d302494c1f8b024ee78a46/python_crontab-3.3.0-py3-none-any.whl", hash = "sha256:739a778b1a771379b75654e53fd4df58e5c63a9279a63b5dfe44c0fcc3ee7884", size = 27533, upload-time = "2025-07-13T20:05:34.266Z" },
]
[[package]]
name = "python-dateutil"
version = "2.9.0.post0"

View File

@@ -17,13 +17,18 @@ WOPI_DEFAULT_CONFIGURATION = {
}
@celery_app.on_after_configure.connect
@celery_app.on_after_finalize.connect
def setup_periodic_tasks(sender: Celery, **kwargs):
"""Setup periodic tasks."""
sender.add_periodic_task(
crontab(minute="0"),
crontab(
minute=settings.WOPI_CONFIGURATION_CRONTAB_MINUTE,
hour=settings.WOPI_CONFIGURATION_CRONTAB_HOUR,
day_of_month=settings.WOPI_CONFIGURATION_CRONTAB_DAY_OF_MONTH,
month_of_year=settings.WOPI_CONFIGURATION_CRONTAB_MONTH_OF_YEAR,
),
configure_wopi_clients.s(),
name="configure_wopi_clients_every_hour",
name="configure_wopi_clients",
serializer="json",
)