Django可能会在不久的将来运行任务 [英] Django run tasks (possibly) in the far future

查看:93
本文介绍了Django可能会在不久的将来运行任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个模型 Event .活动结束后,我想向所有受邀用户发送通知(电子邮件,推送等).类似于以下内容:

Suppose I have a model Event. I want to send a notification (email, push, whatever) to all invited users once the event has elapsed. Something along the lines of:

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 时调用 onEventElapsed .请记住,结束可能与当前日期相距几个月.

Now, of course, the crucial part is to invoke onEventElapsed whenever timezone.now() >= event.end. Keep in mind, end could be months away from the current date.

我已经考虑过两种基本方法:

I have thought about two basic ways of doing this:

  1. 使用定期的 cron 作业(例如,每五分钟左右一次),检查最近五分钟内是否发生了任何事件并执行我的方法.

  1. Use a periodic cron job (say, every five minutes or so) which checks if any events have elapsed within the last five minutes and executes my method.

使用 celery 并使用 eta 参数安排 onEventElapsed 将来运行(在模型 save中)方法).

Use celery and schedule onEventElapsed using the eta parameter to be run in the future (within the models save method).

考虑选项1,可能的解决方案可能是 django-celery-beat .但是,以固定的时间间隔运行任务以发送通知似乎有些奇怪.另外,我想到了一个(潜在的)问题,该问题(可能)会导致一个不太优雅的解决方案:

Considering option 1, a potential solution could be django-celery-beat. However, it seems a bit odd to run a task at a fixed interval for sending notifications. In addition I came up with a (potential) issue that would (probably) result in a not-so elegant solution:

  • 每五分钟检查一次过去五分钟内发生的事件吗?似乎有些不稳定,也许某些事件未得到处理(或其他事件收到的通知发送了两次?).可能的工作方式:发送通知后,向模型添加一个布尔字段,该字段设置为 True .

然后,选项2也有问题:

Then again, option 2 also has its problems:

  • 手动更改事件开始/结束日期时间的情况.使用 celery 时,必须存储 taskID (easy,ofc),并在日期更改后撤消任务并发出新任务.但是我已经读到,当处理将来运行的任务时,芹菜存在(特定于设计的)问题:
  • Manually take care of the situation when an event start/end datetime is moved. When using celery, one would have to store the taskID (easy, ofc) and revoke the task once the dates have changed and issue a new task. But I have read, that celery has (design-specific) problems when dealing with tasks that are run in the future: Open Issue on github. I realize how this happens and why it is everything but trivial to solve.

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

Now, I have come across some libraries which could potentially solve my problem:

  • celery_longterm_scheduler (但这是否意味着我不能像以前那样使用芹菜,因为存在差异Scheduler类吗?这也与 django-celery-beat 的可能用法联系在一起...使用这两个框架中的任何一个,仍然可以对作业进行排队(虽然运行时间稍长,但是还没几个月?)
  • django-apscheduler 使用 apscheduler .但是,我找不到任何有关如何处理在不久的将来运行的任务的信息.
  • celery_longterm_scheduler (But does this mean I cannot use celery as I would have before, because of the differend Scheduler class? This also ties into the possible usage of django-celery-beat... Using any of the two frameworks, is it still possible to queue jobs (that are just a bit longer-running but not months away?)
  • django-apscheduler, uses apscheduler. However, I was unable to find any information on how it would handle tasks that are run in the far future.

我处理此问题的方式是否存在根本性缺陷?我很高兴收到您的任何输入.

Is there a fundemantal flaw with the way I am approaching this? Im glad for any inputs you might have.

通知:我知道这很可能是基于观点的,但是,也许我错过了一个非常基本的东西,无论某些人认为它是丑陋还是优雅的.

推荐答案

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

We're doing something like this in the company i work for, and the solution is quite simple.

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

Have a cron / celery beat that runs every hour to check if any notification needs to be sent. Then send those notifications and mark them as done. This way, even if your notification time is years ahead, it will still be sent. Using ETA is NOT the way to go for a very long wait time, your cache / amqp might loose the data.

您可以根据需要缩短间隔时间,但请确保它们不会重叠.

You can reduce your interval depending on your needs, but do make sure they dont overlap.

如果一个小时的时差太大,那么您可以做的就是每小时运行一个调度程序.逻辑就像

If one hour is too huge of a time difference, then what you can do is, run a scheduler every hour. Logic would be something like

  1. 每小时运行一个任务(以下称此调度程序任务),该任务将获取下一小时需要发送的所有通知(通过celery beat)-
  2. 通过apply_async(eta)安排这些通知-这将是实际发送

使用这种方法可以让您同时拥有最佳世界(eta和节拍)

Using that methodology would get you both of best worlds (eta and beat)

这篇关于Django可能会在不久的将来运行任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆