jango: 每天在指定用户本地时间运行进程

32 阅读3分钟

将网站迁移到 Python/Django 后,需要解决一个问题。网站的使用者可以按当地时间安排事件,并且每天都需要执行该事件。目前,有一个 cron 作业(在另一个服务器上)每隔 5 分钟触发一次,看看在接下来的(例如)10 分钟内是否需要安排任何事件。为每个作业存储时间值和用户的本地时区。最佳的解决方案是什么?

huake_00066_.jpg

2、解决方案

目前正在研究一个函数,可以:

  1. 将服务器时间转换为用户本地时间。
  2. 创建一个本地化的 datetime 对象,以当天的时间和用户指定的时间为准。
  3. 检查是否在用户闹钟响起前 10 分钟内。
  4. 如果时间在 23:50-23:59:59 之间,并且用户设置的时间是 00:00-00:10,则用“明天”的日期创建本地化的“今天”。(例如,如果距离午夜还有 2 分钟,而用户希望在 12:01 举行活动,则用明天的日期计算这次活动)。
  5. 安排一个将在不久后触发的任务(线程或其他方式),如果在 10 分钟内。

不是很确定最佳做法。应该:

  1. 不断检查是否有未来要做的事情,并安排短暂的任务?
  2. 提前生成所有时间(可能提前一个月)?
  3. 完全做其他事情?

还可以始终安排“下一个”事件,但担心的是,如果服务器脱机,并且错过了“下一个”事件,那么第二天永远都不会安排该事件。

澄清一下: 存储每个作业的时间和时区(例如,美国东部时间的中午)。 正在纠正夏令时,所以在计算 UTC 时间时,会以 UTC 的今天作为日期,转换为本地时间,然后用它来计算增量。正在使用 pytz 和 normalize() 来确保不会出现任何奇怪的夏令时问题。 确实有上次安排的时间和上次运行的时间,以确保不会重复执行。

查阅了以下解决方案,发现唯一其他的观察是,如果由于某种原因错过安排好的时间,“下一个”时间点永远不会发生,因为那时它已经是过去的事情了。可以编写一个第二个函数来修复任何错过的闹铃。

经过对以下答案的理解,提出了以下不那么糟糕的方案:

有以下字段:

  1. 上次执行事件的时间
  2. 上次安排事件的时间
  3. 下次执行事件的时间
  4. 时间和时区

无论何时更新事件或触发事件,都要计算并设置 next_run_time。它执行以下操作:

  1. 如果有上次运行时间,则计算 next_run_time,至少在未来 2 小时后(通过增加一些缓冲时间来避免夏令时问题)。
  2. 如果该事件从未运行过,则至少安排在未来 15 分钟后(避免同时安排多个事件)。

安排的作业执行以下操作:

  1. 检查所有在未来 15 分钟内有 next_run_time 并且当前未安排的事件。安排所有匹配的事件。

作业安排:

  1. 安排任务,并将作业设置为“现在”已安排。

当任务执行(成功)时:

  1. last_run_time 更新为“现在”。
  2. next_run_time 重新计算。

如果任务失败:

  1. 将作业重新安排在 30 秒后。如果超过阈值(在我的案例中是延迟 3 分钟),则中止任务并为第二天重新计算 next_run_time。这会记录下来,希望不要发生太多次。

这似乎基本上可行,因为每天都会有事件安排,这样可以腾出一些时间来避免一些棘手的问题。