【问题标题】:Django Celerybeat PeriodicTask running far more than expectedDjango Celerybeat PeriodicTask 运行远远超出预期
【发布时间】:2013-04-02 09:30:40
【问题描述】:

我在 Django、Celery、djcelery 和 PeriodicTasks 上苦苦挣扎。

我创建了一个任务来为 Adsense 提取报告以生成实时统计报告。这是我的任务:

import datetime
import httplib2
import logging

from apiclient.discovery import build
from celery.task import PeriodicTask
from django.contrib.auth.models import User
from oauth2client.django_orm import Storage

from .models import Credential, Revenue


logger = logging.getLogger(__name__)


class GetReportTask(PeriodicTask):
    run_every = datetime.timedelta(minutes=2)

    def run(self, *args, **kwargs):
        scraper = Scraper()
        scraper.get_report()


class Scraper(object):
    TODAY = datetime.date.today()
    YESTERDAY = TODAY - datetime.timedelta(days=1)

    def get_report(self, start_date=YESTERDAY, end_date=TODAY):
        logger.info('Scraping Adsense report from {0} to {1}.'.format(
            start_date, end_date))
        user = User.objects.get(pk=1)
        storage = Storage(Credential, 'id', user, 'credential')
        credential = storage.get()
        if not credential is None and credential.invalid is False:
            http = httplib2.Http()
            http = credential.authorize(http)
            service = build('adsense', 'v1.2', http=http)
            reports = service.reports()
            report = reports.generate(
                startDate=start_date.strftime('%Y-%m-%d'),
                endDate=end_date.strftime('%Y-%m-%d'),
                dimension='DATE',
                metric='EARNINGS',
            )
            data = report.execute()
            for row in data['rows']:
                date = row[0]
                revenue = row[1]

                try:
                    record = Revenue.objects.get(date=date)
                except Revenue.DoesNotExist:
                    record = Revenue()
                record.date = date
                record.revenue = revenue
                record.save()
        else:
            logger.error('Invalid Adsense Credentials')

我正在使用 Celery 和 RabbitMQ。这是我的设置:

# Celery/RabbitMQ
BROKER_HOST = "localhost"
BROKER_PORT = 5672
BROKER_USER = "myuser"
BROKER_PASSWORD = "****"
BROKER_VHOST = "myvhost"
CELERYD_CONCURRENCY = 1
CELERYD_NODES = "w1"
CELERY_RESULT_BACKEND = "amqp"
CELERY_TIMEZONE = 'America/Denver'
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'

import djcelery
djcelery.setup_loader()

乍一看似乎一切正常,但打开记录器并观察它运行后,我发现它至少连续运行四次任务 - 有时更多。它似乎也每分钟运行一次,而不是每两分钟运行一次。我尝试将 run_every 更改为使用 crontab,但得到了相同的结果。

我正在使用主管启动 celerybeat。这是我使用的命令:

python manage.py celeryd -B -E -c 1

关于为什么它没有按预期工作的任何想法?

哦,还有一件事,在日期更改后,它会继续使用它第一次运行的日期范围。因此,随着时间的推移,它会继续获取任务开始运行当天的统计信息 - 除非我在某个时候手动运行任务,否则它会更改为我上次手动运行它的日期。谁能告诉我为什么会这样?

【问题讨论】:

  • 您确定您没有同时运行多个节拍实例吗?

标签: django celery celeryd celerybeat djcelery


【解决方案1】:

考虑为此类任务创建一个具有一个工作进程和固定速率的单独队列,只需将任务添加到这个新队列中,而不是直接从 celerybeat 中运行它们。我希望这可以帮助您弄清楚您的代码有什么问题,是 celerybeat 有问题还是您的任务运行时间比预期的要长。

@task(queue='create_report', rate_limit='0.5/m')
def create_report():
    scraper = Scraper()
    scraper.get_report()

class GetReportTask(PeriodicTask):
    run_every = datetime.timedelta(minutes=2)

    def run(self, *args, **kwargs):
        create_report.delay()

在settings.py中

   CELERY_ROUTES = {
     'myapp.tasks.create_report': {'queue': 'create_report'},
   }

启动额外的 celery worker 来处理队列中的任务

celery worker -c 1 -Q create_report -n create_report.local

问题 2. 您的 YESTERDAY 和 TODAY 变量是在类级别设置的,因此在一个线程中它们只设置一次。

【讨论】:

  • 抱歉,我不太确定如何执行您所描述的操作。你能告诉我更多细节吗?
  • 对于问题 2,TODAY 和 YESTERDAY 是全局变量,我将它们移到课堂上,希望能有所帮助。我现在已经完全取出了变量。明天我会知道这是否有效。
  • 我试用了您发布的代码。它解决了这个问题。它现在每 2 分钟运行一次 adsense 任务。实际上,我在 8 个不同的应用程序中有 13 个周期性任务。我必须对每个人做类似的事情吗?它们都运行得太频繁了,但 Adsense 是最糟糕的。
  • 根据我的经验:当不确定是否有另一个队列时,我总是选择单独的队列。在你的情况下,我认为维护 13+ 个队列会相当困难,所以制作一些 - 一个用于小任务,一些队列用于大任务,你最好不要做的一件事是直接从 celerybeat 运行任务,只需将它们路由到其他排队。请将我的答案标记为解决方案。
  • 所以看起来真正的解决方案是速率限制。如果我删除速率限制,它会不断添加任务。那么 PeriodicTask 类甚至可以工作吗?
猜你喜欢
  • 1970-01-01
  • 2017-07-10
  • 2017-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多