Django:每天在指定的用户本地时间运行一个进程

时间:2013-06-29 20:57:23

标签: python django cron timezone schedule

我将我的网站移植到python / django,其中一个主要练习涉及一组数据,用户可以在当地时间安排活动,并让它每天都有。

目前我有一个cron作业(在另一台服务器上),每隔5分钟点击一个方法,看看是否有什么需要安排在下一个(比方说)10分钟。

我存储时间值,以及每个作业的用户本地时区

这样做的最佳方式是什么?

现在我正在开发一个功能:

  • 将服务器时间转换为用户本地时间。
  • 创建本地日期时间对象本地化为“今天”和用户指定的时间
  • 检查是否在用户闹钟响起的10分钟内。
  • 如果介于23:50-23:59:59之间,则用户设定的时间为00:00-00:10 本地化的“今天”是在“明天”的日期创建的。 (例如,如果它 是2分钟到午夜,用户想要参加活动 12:01,我用明天的日期来计算事件)
  • 我订了一个 调度时的last_scheduled字段和last_fired字段 确保我不发送倍数。

如果是在10分钟之内,我会安排一个即将启动的任务(线程,等等)。

这里不太确定最佳做法。我应该:
继续检查以后我是否有任何工作并安排短期任务? 提前预先生成所有时间(可能一次一个月?)
完全做其他事情?
我也在想我可以随时安排“下一次”活动,但我担心的是,如果说我的服务器脱机了,我错过了“下一次”活动,第二天就永远不会安排。

澄清:

  • 我存储每个工作的时间和时区(例如,美国/东部的中午)。
  • 我正在纠正DST,所以在计算UTC时间时,我将今天的日期改为utc,转换为当地时间,然后用它来计算增量。我正在使用pytz和normalize()来确保我没有得到任何不稳定的DST问题。
  • 我确实有最后安排和最后一次运行的时间,以确保我不会双重执行。

看看下面的解决方案,我想我唯一的另一个观察是,如果无论出于什么原因我错过了预定的时间,我的“下一个”将永远不会发生,因为那是在过去。我想我可以做第二个功能来修复任何错过的警报。

修改: 在解决了下面的答案之后,我提出了以下更糟糕的情况:

我有以下字段

  • 上次活动执行时间
  • 上次安排活动
  • 下一个事件执行时间
  • 时间和时区

每当I:我计算并设置next_run_time:更新事件或触发事件。 这样做如下:

  • 如果它有上次运行时间,则计算next_run_time,将来至少2小时(通过添加一些填充来避免DST问题)。
  • 如果事件从未运行过,请至少安排15分钟(避免任何多个同步时间表)

我的预定工作执行以下操作:

  1. 检查在接下来的15分钟内具有next_run_time的所有事件,并且当前未安排。任何匹配都是预定的。
  2. 安排工作:

    • 安排任务,并按计划“现在”
    • 设置作业

    任务执行时(成功):

    • last_run_time已更新为“now”
    • next_run_time重新计算

    如果任务失败:   - 这项工作将来会重新安排30秒。如果超过阈值(在我的情况下超过3分钟),则任务将中止,并在第二天重新计算next_run_time。这会被记录下来并且希望不会发生太多

    这似乎主要起作用,因为我的事件总是(每天),所以我有能力在时间中抛出一些填充物并避免一些毛茸茸的问题

2 个答案:

答案 0 :(得分:3)

(我会将此作为评论,但SO不允许新用户使用) 看看芹菜,也许它会有所帮助http://docs.celeryproject.org/en/latest/userguide/tasks.html

答案 1 :(得分:2)

我将不再使用Python / Django细节,因为那不是我的专业领域。但一般而言,您所描述类型的任务调度程序应如下所示(恕我直言):

  • 将计划定义与执行时间分开
  • 应在用户本地时间定义计划定义,并包括时区ID。
  • 执行时间应以UTC为单位。
  • 当任务执行时,它应该从计划中计算下一个执行时间。

让我们来看一个例子。

  • 用户说:“美国东部时间每晚午夜运行”。
  • 我们存储“每日,00:00,America/New_York”的时间表。
  • 我们将第一个执行时间计算为2013-06-30T04:00:00Z
  • 使用您喜欢的任何机制,在执行时运行作业。如果要定期轮询需要运行的作业,只需查看时间是否已过(ExecTime< = utcnow)。如果您可以依赖事件系统,cron作业等,那可能会更好。
  • 当作业运行时,使用计划来计算下一个执行时间。

为什么要在当地时间安排?那么,在东部时间的情况下,由于夏令时,它将从UTC到-5小时之间转换到-4小时。如果时间表严格基于UTC,那么在DST转换之后,您会发现作业以用户认为错误的时间运行。

此外,您应该考虑处理故障,重试等。并且您不希望每个计划执行的作业多次运行,因此您可能想要一种方法将其标记为“正在处理中”,如果您有不止一个程序检查任务。有时您可能需要更复杂的锁定策略来确保多个工作进程不会执行相同的任务。这有点超出了我在这里写的范围。

您还应该考虑如何处理由夏令时转换引起的本地时间的歧义。考虑到“后退”风格转换,如果用户说要在“每晚凌晨1:30”运行,但是每年有一个晚上1:30发生两次,你想做什么?如果你没有做任何特别的事情,它将在第一次出现时运行 - 通常是白天时间。用户可能期望标准时间,因此您可能需要检查此时间。即使你只是在午夜跑,你也不能免除这个决定。有几个时区在午夜时分(例如巴西)进行过渡。

如果所有这些听起来都太过分,那么您可能只想查找已编写的作业调度程序。例如,Java上的Quartz或.Net堆栈上的Quartz.Net。我并不直接熟悉它,但是Python的搜索结果显示APScheduler,看起来非常相似。