0

Snippet from my tasks.py file are as follows:

from celery.task.schedules import crontab
from celery.decorators import periodic_task

@periodic_task(
    run_every=crontab(minute='15, 45', hour='0, 7, 15'),
)
def task1():
    send_mail()

I want the script in task1() to be triggered only at 00:15, 7:15 and 15:45, whereas with the current settings it's triggered at 00:15, 00:45, 7:15, 7:45, 15:15 and 15:45.

How do I do this ? Also, let me know if there is a better approach!

Virat
  • 129
  • 4
  • 20

2 Answers2

1

After reading through the documentation, and borrowing some ideas from here, I went about solving this as follows:

  1. Removing the periodic_task decorator and updating the tasks.py as:

    from celery.task.schedules import crontab
    from celery.decorators import periodic_task
    
    @task
    def task1():
        send_mail()
    
  2. Add the beat schedule in celery.py as:

    app.conf.beat_schedule = {
        'alert': {
            'task': 'app.tasks.task1',
            'schedule': crontab(minute='15', hour='0, 7')
        },
        'custom_alert': {
            'task': 'app.tasks.task1',
            'schedule': crontab(minute='45', hour='15')
        }
    }
    

With these settings, the script in task1() is getting triggered only at desired time (0:15, 7:15 and 15:45)!

Virat
  • 129
  • 4
  • 20
0

You have two options. One is to define the decorated function a few times:

def _task1():
    send_mail()

task1_a = @periodic_task(
    _task1,
    run_every=crontab(minute='15', hour='0, 7'),
)
task1_b = @periodic_task(
    _task1,
    run_every=crontab(minute='45', hour='15'),
)

The other option is to define a custom schedule implementing celery's schedule interface.

schillingt
  • 13,493
  • 2
  • 32
  • 34
  • I don't think we can assign decorators to variables! I am exploring the second option, but can you please elaborate more on the first method ? – Virat Nov 26 '19 at 05:24
  • 1
    Yes you can. Python is a language that has first-class functions. They are effectively objects in their own right. All a decorator does is wrap the internal function. So rather than defining the internal function twice or creating a new function that calls the internal, you use the decorator twice to wrap the function creating two new functions. – schillingt Nov 26 '19 at 14:09
  • Although I'm aware of first-class functions in Python, I didn't think it was possible to use decorators this way! As for the given question, the first method ( that of assigning decorators to variables) throws a syntax error. – Virat Nov 26 '19 at 16:47