amichib amichib - 2 months ago 11
Python Question

run celery tasks in random times

i need to run few celery tasks in random times - every run should be at a new random time - the random number should generated every run.

what I did in the past is:


"my_task": {
"task": "path.to.my_task",
"schedule": crontab(minute='*/%s' % rand),
},
rand = random(1,12)


but this code is not good for my needs anu more:

1. I need different (as possible with random0 number for each tenant

2. different number will generated every time and not only on settings.py load (once)


I tried to overwrite Schedule as explained in THIS answer but it did not work, is there better way? am I missing something?

(for example in tenant A the task will run at 23 and the day after at 8, and in tenant B the task will run at 4 and the day after at 20 etc)

Thanks!

======== update ====

after the great answer I got, I added option to my task and process it in apply_asynch method as suggested-
.

"my-task": { # deprecated task
"task": "mdm_sync.tasks.test_task",
# "schedule": new_sc(),
"schedule": crontab(minute=39, hour=11),
"options": {
"eta": datetime.utcnow()
}
},





entry.options["eta"] = datetime.datetime.utcnow() + datetime.timedelta(seconds=random(3600,12*3600)


works great!

Answer

I faced a similar problem in which i had to generate facebook like notifications between random users at random interval of time

Initially i was also doing the same as you, using the random function to give the minute value to crontab. But, as settings.py and celery.py are loaded only once when you hit python manage.py runserver, that random function runs only once and hence that random value is selected only once, say 5 minutes or 7 minutes, but then this random value is used for repeating the task at every 5 or 7 minutes, hence making the tasks repeat periodically.

So, what you need to do is that instead of defining the timing of task in settings.py or celery.py you need to recursively call the function/ method in your tasks.py. But the key here is that you need to call the same function recursively and asynchronously, and while calling it asynchronously, you need to pass a parameter delay whose value will be calculated by using the random function

See my tasks.py -> https://github.com/ankushrgv/notification/blob/master/apps/notifications/tasks.py

And

celery.py -> https://github.com/ankushrgv/notification/blob/master/config/celery.py

You'll have to python manage.py shell and then call the function / method from there only once to start the recursion.

something like

`myFunction().apply_async()`

In my case it used to be

`CreateNotifications().apply_async()`