From c1925e9b3212f26212d31844c7e04193797c1d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Wed, 4 Dec 2019 15:10:38 +0100 Subject: [PATCH] cron: add random minutes offset to all jobs, at evaluation time (#38200) SECRET_KEY is not available early enough in uwsgi context and the behaviour doesn't need to be optional. --- wcs/formdef.py | 4 ++-- wcs/publisher.py | 2 +- wcs/qommon/cron.py | 13 +++++++------ wcs/qommon/ident/password.py | 4 ++-- wcs/qommon/publisher.py | 4 ++-- wcs/wf/aggregation_email.py | 2 +- wcs/wf/jump.py | 9 +++------ 7 files changed, 18 insertions(+), 20 deletions(-) diff --git a/wcs/formdef.py b/wcs/formdef.py index bb6f48e6d..ce1b9153e 100644 --- a/wcs/formdef.py +++ b/wcs/formdef.py @@ -1659,8 +1659,8 @@ if get_publisher_class(): # once a month, look for drafts to remove get_publisher_class().register_cronjob(CronJob(clean_drafts, name='clean_drafts', - days=[2], hours=[0], minutes=[0], hourly=True)) + days=[2], hours=[0], minutes=[0])) # once a day, look for unused files get_publisher_class().register_cronjob(CronJob(clean_unused_files, name='clean_unused_files', - hours=[2], minutes=[0], hourly=True)) + hours=[2], minutes=[0])) diff --git a/wcs/publisher.py b/wcs/publisher.py index afca3bec9..555b43969 100644 --- a/wcs/publisher.py +++ b/wcs/publisher.py @@ -122,7 +122,7 @@ class WcsPublisher(StubWcsPublisher): def register_cronjobs(cls): super(WcsPublisher, cls).register_cronjobs() # every hour: check for global action timeouts - cls.register_cronjob(CronJob(cls.apply_global_action_timeouts, hourly=True)) + cls.register_cronjob(CronJob(cls.apply_global_action_timeouts, minutes=[0])) def is_using_postgresql(self): return bool(self.has_site_option('postgresql') and self.cfg.get('postgresql', {})) diff --git a/wcs/qommon/cron.py b/wcs/qommon/cron.py index e08086aff..46843d559 100644 --- a/wcs/qommon/cron.py +++ b/wcs/qommon/cron.py @@ -26,17 +26,13 @@ class CronJob(object): days = None function = None - def __init__(self, function, name=None, hours=None, minutes=None, weekdays=None, days=None, hourly=False): + def __init__(self, function, name=None, hours=None, minutes=None, weekdays=None, days=None): self.function = function self.name = name self.hours = hours self.minutes = minutes self.weekdays = weekdays self.days = days - if hourly: - # set minutes to an arbitrary value based on installation, this - # prevents waking up all jobs at the same time on a server farm. - self.minutes = [ord(settings.SECRET_KEY[-1]) % 60] def cron_worker(publisher, now, job_name=None): try: @@ -55,13 +51,18 @@ def cron_worker(publisher, now, job_name=None): if job.name != job_name: continue else: + minutes = job.minutes + if minutes: + # will set minutes to an arbitrary value based on installation, this + # prevents waking up all jobs at the same time on a container farm. + minutes = [(x + ord(settings.SECRET_KEY[-1])) % 60 for x in minutes] if job.days and now[2] not in job.days: continue if job.weekdays and now[6] not in job.weekdays: continue if job.hours and not now[3] in job.hours: continue - if job.minutes and not now[4] in job.minutes: + if minutes and not now[4] in minutes: continue class FakeRequest(object): diff --git a/wcs/qommon/ident/password.py b/wcs/qommon/ident/password.py index 7f730f449..b7039b8ca 100644 --- a/wcs/qommon/ident/password.py +++ b/wcs/qommon/ident/password.py @@ -1692,6 +1692,6 @@ def handle_expired_tokens(publisher): if get_publisher_class(): # at 6:00 in the morning, every day get_publisher_class().register_cronjob( - CronJob(handle_unused_accounts, minutes=[0], hours=[6], hourly=True)) + CronJob(handle_unused_accounts, minutes=[0], hours=[6])) get_publisher_class().register_cronjob( - CronJob(handle_expired_tokens, minutes=[10], hours=[6], hourly=True)) + CronJob(handle_expired_tokens, minutes=[0], hours=[6])) diff --git a/wcs/qommon/publisher.py b/wcs/qommon/publisher.py index 7a4820554..ff746278d 100644 --- a/wcs/qommon/publisher.py +++ b/wcs/qommon/publisher.py @@ -631,8 +631,8 @@ class QommonPublisher(Publisher, object): def register_cronjobs(cls): cls.register_cronjob(CronJob(cls.clean_sessions, minutes=range(0, 60, 5))) cls.register_cronjob(CronJob(cls.clean_nonces, minutes=range(0, 60, 5))) - cls.register_cronjob(CronJob(cls.clean_afterjobs, hourly=True)) - cls.register_cronjob(CronJob(cls.clean_tempfiles, hourly=True)) + cls.register_cronjob(CronJob(cls.clean_afterjobs, minutes=[0])) + cls.register_cronjob(CronJob(cls.clean_tempfiles, minutes=[0])) _initialized = False @classmethod diff --git a/wcs/wf/aggregation_email.py b/wcs/wf/aggregation_email.py index cfd09cbab..d70c904e7 100644 --- a/wcs/wf/aggregation_email.py +++ b/wcs/wf/aggregation_email.py @@ -156,4 +156,4 @@ def send_aggregation_emails(publisher): if get_publisher_class(): # at 6:00 in the morning, every day but the week end get_publisher_class().register_cronjob( - CronJob(send_aggregation_emails, hours=[6], minutes=[0], hourly=True, weekdays=range(5))) + CronJob(send_aggregation_emails, hours=[6], minutes=[0], weekdays=range(5))) diff --git a/wcs/wf/jump.py b/wcs/wf/jump.py index 516dd85fc..37500a026 100644 --- a/wcs/wf/jump.py +++ b/wcs/wf/jump.py @@ -19,7 +19,6 @@ import json import os import sys -from django.conf import settings from django.utils import six from quixote import get_publisher, get_request, redirect @@ -303,11 +302,9 @@ def _apply_timeouts(publisher): if get_publisher_class(): # every JUMP_TIMEOUT_INTERVAL minutes check for expired status jump - # timeouts; align checks with the "hourly" check defined in - # wcs/qommon/cron.py - minutes = [(x + ord(settings.SECRET_KEY[-1])) % 60 - for x in range(0, 60, JUMP_TIMEOUT_INTERVAL)] + # timeouts. get_publisher_class().register_cronjob( CronJob(_apply_timeouts, name='evaluate_jumps', - hours=range(24), minutes=minutes)) + hours=range(24), + minutes=range(0, 60, JUMP_TIMEOUT_INTERVAL)))