Django在遥远的将来运行任务(可能)

2024-10-03 23:27:55 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个模型Event。我想在活动结束后向所有受邀用户发送通知(电子邮件、推送等)。大致如下:

class Event(models.Model):
    start = models.DateTimeField(...)
    end = models.DateTimeField(...)
    invited = models.ManyToManyField(model=User)

    def onEventElapsed(self):
        for user in self.invited:
           my_notification_backend.sendMessage(target=user, message="Event has elapsed")

当然,现在关键的部分是在任何时候调用timezone.now() >= event.end。 请记住,end可能离当前日期还有几个月

我考虑过两种基本的方法:

  1. 使用一个周期性的cron作业(比如,每五分钟左右一次),它检查过去五分钟内是否发生了任何事件,并执行我的方法

  2. 使用celery并使用eta参数调度onEventElapsed,以便将来运行(在modelssave方法中)

考虑到备选方案1,可能的解决办法是django-celery-beat。但是,以固定的时间间隔运行任务以发送通知似乎有点奇怪。此外,我还提出了一个(潜在)问题,该问题可能导致(可能)一个不那么优雅的解决方案:

  • 是否每五分钟检查一次前五分钟内发生的事件?看起来有些不稳定,可能有些活动错过了(或者其他人收到了两次通知?)。可能的解决方法:向模型添加一个布尔字段,该字段在发送通知后设置为True

同样,方案2也有其问题:

  • 手动处理移动事件开始/结束日期时间时的情况。在使用celery时,必须存储taskID(easy,ofc),并在日期更改后撤销任务,并发出新任务。但是我已经读到,芹菜在处理将来运行的任务时有(特定于设计的)问题:Open Issue on github。我意识到这是如何发生的,以及为什么它除了琐碎的问题外什么都不需要解决

现在,我遇到了一些可能解决我的问题的库:

  • celery_longterm_scheduler(但这是否意味着我不能像以前那样使用芹菜,因为调度程序类不同?这也与django-celery-beat的可能用法有关…使用这两个框架中的任何一个,是否仍然可以对作业进行排队(运行时间稍长,但不是几个月之后?)
  • django-apscheduler,使用apscheduler。但是,我找不到任何关于它如何处理在遥远的将来运行的任务的信息

我处理这件事的方式有没有根本的缺陷?我很高兴你能提供任何意见

注意:我知道这可能是基于某种观点的,但是,也许有一件非常基本的事情我错过了,不管有些人认为什么是丑陋或优雅的。


Tags: django方法模型selfeventmodels作业时间
1条回答
网友
1楼 · 发布于 2024-10-03 23:27:55

在我工作的公司,我们正在做类似的事情,解决方案非常简单

每小时运行一次cron/芹菜节拍,检查是否需要发送任何通知。 然后发送这些通知并将其标记为完成。这样,即使您的通知时间提前了几年,它仍然会被发送。在很长的等待时间内,使用ETA不是最好的方法,您的缓存/amqp可能会丢失数据

你可以根据自己的需要缩短间隔时间,但一定要确保它们不会重叠

如果一个小时的时差太大,那么您可以做的是,每小时运行一个调度程序。逻辑大概是这样的

  1. 每小时运行一个任务(让我们调用此调度程序任务),获取下一小时需要发送的所有通知(通过芹菜节拍)——
  2. 通过apply_async(eta)计划这些通知-这将是实际发送

使用这种方法可以让你们两个都获得最佳世界(eta和beat)

相关问题 更多 >