为啥django-q定时任务会随机延迟?

Posted

技术标签:

【中文标题】为啥django-q定时任务会随机延迟?【英文标题】:Why are django-q scheduled tasks delayed randomly?为什么django-q定时任务会随机延迟? 【发布时间】:2021-09-26 21:46:11 【问题描述】:

我发现 django-q 没有按时执行我安排的任务。可能会有几秒到近一分钟的延迟。

我这样安排一个任务:

from django.utils import timezone
from django_q.models import Schedule

def schedule_auction_deadlines(self):
    now = timezone.now()
    if self.deadline:
        name = "end_phase_%d" % self.id
        Schedule.objects.filter(name=name).delete()
        if now < self.deadline:
            Schedule.objects.create(name=name, func="myapp.views.end_phase", args=str(self.id), next_run=self.deadline, schedule_type=Schedule.ONCE)

这是我在 settings.py 文件中的配置:

Q_CLUSTER = 
    'name': 'myproj',
    'label': 'Django Q',
    'timeout': 30,
    'catch_up': True,
    'guard_cycle': 1,
    'redis': os.environ.get('REDIS_URL', 'redis://localhost:6379'),

从文档看来,guard_cycle 可能是相关的,但我已经将它设置为最低设置。

什么可能导致这些延迟?

【问题讨论】:

【参考方案1】:

我发现 django-q 没有按时执行我安排的任务。可能会有几秒到近一分钟的延迟。

根据the docs,调度器每三十秒才检查一次,所以需要30-40秒也就不足为奇了。

从文档看来,guard_cycle 可能是相关的,但我已经将它设置为最低设置。

保护周期实际上默认为 0.5,因此您将其设置为高于默认值。但是调度程序间隔的实现有点奇怪,因为设置较低的保护时间实际上可以增加调度程序检查之间的时间量。

重要代码在Sentinel.guard:

def guard(self):
    logger.info(
        _(
            f"current_process().name guarding cluster humanize(self.cluster_id.hex)"
        )
    )
    self.start_event.set()
    Stat(self).save()
    logger.info(_(f"Q Cluster humanize(self.cluster_id.hex) running."))
    counter = 0
    cycle = Conf.GUARD_CYCLE  # guard loop sleep in seconds
    # Guard loop. Runs at least once
    while not self.stop_event.is_set() or not counter:
        # Check Workers
        [...]
        # Check Monitor
        [...]
        # Check Pusher
        [...]
        # Call scheduler once a minute (or so)
        counter += cycle
        if counter >= 30 and Conf.SCHEDULER:
            counter = 0
            scheduler(broker=self.broker)
        # Save current status
        Stat(self).save()
        sleep(cycle)
    self.stop()

所以调度程序不会每次都通过循环调用。只在每次counter大于30时调用,counter每次按guard_cycle递增。如果将 guard_cycle 设置为 0.001,则守卫将仅通过循环每 30,000 次调用调度程序一次,这将花费超过 30 秒,因为守卫在检查集群的健康状况方面所做的所有其他工作。

由于调度程序间隔是硬编码的,除了修改 Django Q 或自己调用调度程序之外,我看不出你能做什么。文档没有说明如何执行此操作。

【讨论】:

以上是关于为啥django-q定时任务会随机延迟?的主要内容,如果未能解决你的问题,请参考以下文章

linux初学者-延迟及定时任务篇

系统定时延迟任务及定时任务

我的linux定时任务不起作用是为啥?

我的linux定时任务不起作用是为啥?

系统延迟及定时机制

Java分布式定时任务场景的思考与设计