diff --git a/authentik/admin/settings.py b/authentik/admin/settings.py index 3072c339e..beabfd4a6 100644 --- a/authentik/admin/settings.py +++ b/authentik/admin/settings.py @@ -1,10 +1,12 @@ """authentik admin settings""" from celery.schedules import crontab +from authentik.lib.utils.time import fqdn_rand + CELERY_BEAT_SCHEDULE = { "admin_latest_version": { "task": "authentik.admin.tasks.update_latest_version", - "schedule": crontab(minute="*/60"), # Run every hour + "schedule": crontab(minute=fqdn_rand("admin_latest_version", 60), hour="*"), "options": {"queue": "authentik_scheduled"}, } } diff --git a/authentik/crypto/settings.py b/authentik/crypto/settings.py index 598576d48..499a251bf 100644 --- a/authentik/crypto/settings.py +++ b/authentik/crypto/settings.py @@ -1,10 +1,12 @@ """Crypto task Settings""" from celery.schedules import crontab +from authentik.lib.utils.time import fqdn_rand + CELERY_BEAT_SCHEDULE = { "crypto_certificate_discovery": { "task": "authentik.crypto.tasks.certificate_discovery", - "schedule": crontab(minute="*/5"), + "schedule": crontab(minute=fqdn_rand("crypto_certificate_discovery", 60), hour="*"), "options": {"queue": "authentik_scheduled"}, }, } diff --git a/authentik/lib/utils/time.py b/authentik/lib/utils/time.py index 108e39ea2..d820f7263 100644 --- a/authentik/lib/utils/time.py +++ b/authentik/lib/utils/time.py @@ -1,6 +1,10 @@ """Time utilities""" import datetime +from hashlib import sha256 +from random import randrange, seed +from socket import getfqdn +from celery.schedules import crontab from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ @@ -38,3 +42,12 @@ def timedelta_from_string(expr: str) -> datetime.timedelta: if len(kwargs) < 1: raise ValueError("No valid keys to pass to timedelta") return datetime.timedelta(**kwargs) + + +def fqdn_rand(task: str, max: int) -> int: + """Get a random number within max based on the FQDN and task name""" + entropy = f"{getfqdn()}:{task}" + hasher = sha256() + hasher.update(entropy.encode("utf-8")) + seed(hasher.hexdigest()) + return randrange(0, max) # nosec diff --git a/authentik/managed/settings.py b/authentik/managed/settings.py index 1784ef2a2..924376e8f 100644 --- a/authentik/managed/settings.py +++ b/authentik/managed/settings.py @@ -1,10 +1,12 @@ """managed Settings""" from celery.schedules import crontab +from authentik.lib.utils.time import fqdn_rand + CELERY_BEAT_SCHEDULE = { "managed_reconcile": { "task": "authentik.managed.tasks.managed_reconcile", - "schedule": crontab(minute="*/5"), + "schedule": crontab(minute=fqdn_rand("managed_reconcile", 60), hour="*/4"), "options": {"queue": "authentik_scheduled"}, }, } diff --git a/authentik/outposts/settings.py b/authentik/outposts/settings.py index bd0e9a94e..b2a876f42 100644 --- a/authentik/outposts/settings.py +++ b/authentik/outposts/settings.py @@ -1,25 +1,27 @@ """Outposts Settings""" from celery.schedules import crontab +from authentik.lib.utils.time import fqdn_rand + CELERY_BEAT_SCHEDULE = { "outposts_controller": { "task": "authentik.outposts.tasks.outpost_controller_all", - "schedule": crontab(minute="*/5"), + "schedule": crontab(minute=fqdn_rand("outposts_controller", 60), hour="*/4"), "options": {"queue": "authentik_scheduled"}, }, "outposts_service_connection_check": { "task": "authentik.outposts.tasks.outpost_service_connection_monitor", - "schedule": crontab(minute="*/5"), + "schedule": crontab(minute="3-59/15"), "options": {"queue": "authentik_scheduled"}, }, "outpost_token_ensurer": { "task": "authentik.outposts.tasks.outpost_token_ensurer", - "schedule": crontab(minute="*/5"), + "schedule": crontab(minute=fqdn_rand("outpost_token_ensurer", 60), hour="*/8"), "options": {"queue": "authentik_scheduled"}, }, "outpost_local_connection": { "task": "authentik.outposts.tasks.outpost_local_connection", - "schedule": crontab(minute="*/60"), + "schedule": crontab(minute=fqdn_rand("outpost_local_connection", 60), hour="*/8"), "options": {"queue": "authentik_scheduled"}, }, } diff --git a/authentik/policies/reputation/settings.py b/authentik/policies/reputation/settings.py index 12b583fb7..b51ecc187 100644 --- a/authentik/policies/reputation/settings.py +++ b/authentik/policies/reputation/settings.py @@ -4,7 +4,7 @@ from celery.schedules import crontab CELERY_BEAT_SCHEDULE = { "policies_reputation_save": { "task": "authentik.policies.reputation.tasks.save_reputation", - "schedule": crontab(minute="*/5"), + "schedule": crontab(minute="1-59/5"), "options": {"queue": "authentik_scheduled"}, }, } diff --git a/authentik/root/settings.py b/authentik/root/settings.py index b8fedb4c8..055cc3f45 100644 --- a/authentik/root/settings.py +++ b/authentik/root/settings.py @@ -337,17 +337,12 @@ CELERY_WORKER_MAX_TASKS_PER_CHILD = 50 CELERY_BEAT_SCHEDULE = { "clean_expired_models": { "task": "authentik.core.tasks.clean_expired_models", - "schedule": crontab(minute="*/5"), - "options": {"queue": "authentik_scheduled"}, - }, - "db_backup": { - "task": "authentik.core.tasks.backup_database", - "schedule": crontab(hour="*/24", minute=0), + "schedule": crontab(minute="2-59/5"), "options": {"queue": "authentik_scheduled"}, }, "user_cleanup": { "task": "authentik.core.tasks.clean_temporary_users", - "schedule": crontab(minute="*/5"), + "schedule": crontab(minute="9-59/5"), "options": {"queue": "authentik_scheduled"}, }, } diff --git a/authentik/sources/ldap/settings.py b/authentik/sources/ldap/settings.py index 224b240ac..5da815856 100644 --- a/authentik/sources/ldap/settings.py +++ b/authentik/sources/ldap/settings.py @@ -1,10 +1,12 @@ """LDAP Settings""" from celery.schedules import crontab +from authentik.lib.utils.time import fqdn_rand + CELERY_BEAT_SCHEDULE = { "sources_ldap_sync": { "task": "authentik.sources.ldap.tasks.ldap_sync_all", - "schedule": crontab(minute="*/120"), # Run every other hour + "schedule": crontab(minute=fqdn_rand("sources_ldap_sync", 60), hour="*/2"), "options": {"queue": "authentik_scheduled"}, } } diff --git a/authentik/sources/plex/settings.py b/authentik/sources/plex/settings.py index bfd5d1947..ebd8ae0c2 100644 --- a/authentik/sources/plex/settings.py +++ b/authentik/sources/plex/settings.py @@ -1,10 +1,12 @@ """Plex source settings""" from celery.schedules import crontab +from authentik.lib.utils.time import fqdn_rand + CELERY_BEAT_SCHEDULE = { "check_plex_token": { "task": "authentik.sources.plex.tasks.check_plex_token_all", - "schedule": crontab(minute="31", hour="*/3"), + "schedule": crontab(minute=fqdn_rand("check_plex_token", 60), hour="*/3"), "options": {"queue": "authentik_scheduled"}, }, }