【问题标题】:When I use Django Celery apply_async with eta, it does the job immediately当我将 Django Celery apply_async 与 eta 一起使用时,它会立即完成工作
【发布时间】:2017-12-18 10:18:59
【问题描述】:

我查看了 celery 文档并从中尝试了一些东西,但它不像示例那样工作。也许我在某些时候错了,如果我对以下代码有误,请给我一些指导

在views.py中我有这样的东西:

class Something(CreateView):
  model = something

  def form_valid(self, form):
    obj = form.save(commit=False)
    number = 5
    test_limit = datetime.now() + timedelta(minutes=5)
    testing_something.apply_async((obj, number), eta=test_limit)
    obj.save()

在芹菜任务中我写了这样的东西:

@shared_task()
def add_number(obj, number):
    base = Base.objects.get(id=1)
    base.add = base.number + number
    base.save()
return obj

我使用此代码的条件是 celery 在 CreateView 运行后立即运行,我的目标是在运行 Something CreateView 后 5 分钟内运行一次任务 add_number。非常感谢

编辑:

  1. 我已尝试将eta 更改为countdown=180,但它仍会立即运行add_number 功能。我也尝试过更长的倒计时,但仍会立即运行
  2. 我试过@johnmoustafis 的回答,但还是一样,任务立即运行
  3. 我也试过@dana 的回答,但还是一样,任务立即运行

【问题讨论】:

    标签: python django celery django-celery celery-task


    【解决方案1】:

    Celery 默认使用 UTC 时间。
    如果您的时区“落后”于 UTC(UTC - HH:MM),datetime.now() 调用将返回一个“落后于”UTC 的时间戳,从而导致您的任务立即执行。

    您可以改用datetime.utcnow()

    test_limit = datetime.utcnow() + timedelta(minutes=5)
    

    由于您使用的是 django,因此存在另一种选择:

    如果您在setting.py 中设置了USE_TZ = True,则您已启用django timezone settings,您可以使用timezone.now() 代替datetime.utcnow()

    from django.utils import timezone
    
    ...
    
    test_limit = timezone.now() + timedelta(minutes=5)
    

    【讨论】:

    • 我已经尝试过 timezone.now() 和 datetime.utcnow() 即使我刚刚尝试使用 my_date = datetime.now(pytz.timezone('US/Pacific')) 但仍然是一样
    • @knightzoid 您是否在django.settings 中设置了适当的时区? docs.djangoproject.com/en/1.11/ref/settings/…
    • 是的,我在settings.py中设置了时区TIME_ZONE = 'US/Pacific'
    • 我已经使用pdb 在终端上进行了一些调试,所以我可以看到time_limit 的确切时间,但它对我来说显示了正确的时间
    • @knightzoid 尝试用countdown=time_in_seconds 替换eta,以检查这是否与预期的延迟有关,或者问题出在其他地方。还可以尝试设置CELERY_ALWAYS_EAGER=False 并使用timezone.now() 等重试。
    【解决方案2】:

    'test_limit' 变量没有时区信息。所以 Celery 会将 eta 参数理解为 UTC 时间。

    请使用修改后的代码:

    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()
    

    【讨论】:

      【解决方案3】:

      您可能有CELERY_ALWAYS_EAGER=True 设置。

      您能否也发布您的配置和您正在使用的 Celery 版本?

      Here你可能会找到一些有用的信息。

      【讨论】:

      • 我将CELERY_ALWAYS_EAGER 更改为False,但还是一样。我使用celery==3.1.19,这是我在settings.py 上的芹菜设置CELERY_IMPORTS = ("somewhere.utils.tasks", ) CELERYBEAT_SCHEDULE = { 'send-post-office-mails': { 'task': 'somewhere.utils.tasks.send_post_office_mails', 'schedule': crontab(), }, 'rebuild-index': { 'task': 'somewhere.utils.tasks.rebuild_search_index', 'schedule': crontab(minute=0, hour='*'), }, } CELERY_ALWAYS_EAGER = False
      • 我在您的设置中看到的一些问题是您没有定义BROKER_URL,这可能是问题所在。关注this guide 可能会对您有所帮助。
      • 我使用 redis 作为我的代理,我也把它放在我的 settings.py BROKER_URL = env("DJANGO_BROKER_URL", default='redis://localhost:6379/0')
      猜你喜欢
      • 2018-11-12
      • 1970-01-01
      • 1970-01-01
      • 2015-12-12
      • 2018-09-12
      • 2014-09-01
      • 2015-06-06
      • 2015-08-29
      • 1970-01-01
      相关资源
      最近更新 更多