8👍
Celery by default uses UTC time.
If your timezone is “behind” the UTC (UTC – HH:MM) the datetime.now()
call will return a timestamp which is “behind” UTC, thus causing your task to be executed immediately.
You can use datetime.utcnow()
instead:
test_limit = datetime.utcnow() + timedelta(minutes=5)
Since you are using django, there exist another option:
If you have set the USE_TZ = True
in your setting.py
, you have enabled the django timezone settings and you can use timezone.now()
instead of datetime.utcnow()
:
from django.utils import timezone
...
test_limit = timezone.now() + timedelta(minutes=5)
1👍
‘test_limit’ variable hasn’t got timezone information. So Celery will understand eta param as UTC time.
Please use modified code:
class Something(CreateView):
model = something
def form_valid(self, form):
obj = form.save(commit=False)
number = 5
test_limit = datetime.now()
test_limit = test_limit.replace(tzinfo=tz.tzlocal())
test_limit = test_limit + timedelta(minutes=5)
testing_something.apply_async((obj, number), eta=test_limit)
obj.save()
0👍
You might have the CELERY_ALWAYS_EAGER=True
setting.
Could you also post your configuration and the Celery version you are using?
Here you might find some useful information.
- Django Rest Framework – Nested Serialization not working as expected
- What does "Directory indexes are not allowed here." mean in a Django error?
0👍
I was facing the same issue with celery version 5.1.0 and I got to know that the celery config "CELERY_ALWAYS_EAGER" name has been changed to "CELERY_TASK_ALWAYS_EAGER" in version 4.0+.
So make sure you have set CELERY_TASK_ALWAYS_EAGER=False
if you are using celery version 4.0+
Celery task with apply_async method should execute with specified delay in eta or countdown and both should work according to apply_async definition
def apply_async(self, args=None, kwargs=None, task_id=None, producer=None,
link=None, link_error=None, shadow=None, **options):
"""Apply tasks asynchronously by sending a message.
Arguments:
args (Tuple): The positional arguments to pass on to the task.
kwargs (Dict): The keyword arguments to pass on to the task.
countdown (float): Number of seconds into the future that the
task should execute. Defaults to immediate execution.
eta (~datetime.datetime): Absolute time and date of when the task
should be executed. May not be specified if `countdown`
is also supplied.
expires (float, ~datetime.datetime): Datetime or
seconds in the future for the task should expire.
The task won't be executed after the expiration time.
Following code works fine for me.
item/tasks.py
@app.task
def delete_item(item_pk):
try:
item = Item.objects.get(pk=item_pk)
item.delete()
except ObjectDoesNotExist:
logging.warning(f"Cannot find item with id: {item_pk}.")
Now you can call this function in your logic in the following ways:
...
delete_item.apply_async((item.pk,), countdown=60) # execute after 1 minute
...
(or)
from datetime import datetime, timedelta
...
eta = datetime.now() + timedelta(seconds=60)
delete_item.apply_async((item.pk,), eta=eta) # execute after 1 minute
...
- How to create charts with Plotly on Django?
- Customize the djoser create user endpoint
- Django's "dumpdata" or Postgres' "pg_dump"?