Search code examples
djangocelerydjango-celerycelery-task

Django celery: scheduling recurring task but with fixed start date


At the moment djcelery allows me to schedule a recurring task via the PeriodicTask model. For example a task that runs on an interval like every minute, or an interval specified by a crontab like every 1st of the month at noon. What I'd really like to do however is schedule a task for a fixed date that then repeats on an interval. For example first run on 3 March 2016 at 2:00 and then every hour thereafter.

Is there a way to achieve this within django and celery(with or without djcelery)? Thanks


Solution

  • As it is stated in the docs, you may implement your own custom scheduler. You should override the is_due method, which decides whether it is time to run the task.

    Below is a proof-of-concept (I haven't checked it for errors). Note, that the __reduce__ method is also overridden so that the new parameter gets serialised as well.

    import celery.schedules.schedule
    
    class myschedule(celery.schedules.schedule):
    
        def __init__(self, *args, **kwargs):
            super(myschedule, self).__init__(*args, **kwargs)
            self.start_date = kwargs.get('start_date', None)
    
        def is_due(self, last_run_at):
            if self.start_date is not None and self.now() < self.start_date:
                return (False, 20)  # try again in 20 seconds
            return super(myschedule, self).is_due(last_run_at)
    
        def __reduce__(self):
            return self.__class__, (self.run_every, self.relative, self.nowfun, self.start_date)
    

    And then you use it in the config:

    CELERYBEAT_SCHEDULE = {
        'add-every-30-seconds': {
            'task': 'tasks.add',
            'schedule': myschedule(timedelta(seconds=30), start_date=start_date),
            'args': (16, 16)
        },
    }