将网站迁移到 Python/Django 后,需要解决一个问题。网站的使用者可以按当地时间安排事件,并且每天都需要执行该事件。目前,有一个 cron 作业(在另一个服务器上)每隔 5 分钟触发一次,看看在接下来的(例如)10 分钟内是否需要安排任何事件。为每个作业存储时间值和用户的本地时区。最佳的解决方案是什么?
2、解决方案
目前正在研究一个函数,可以:
- 将服务器时间转换为用户本地时间。
- 创建一个本地化的 datetime 对象,以当天的时间和用户指定的时间为准。
- 检查是否在用户闹钟响起前 10 分钟内。
- 如果时间在 23:50-23:59:59 之间,并且用户设置的时间是 00:00-00:10,则用“明天”的日期创建本地化的“今天”。(例如,如果距离午夜还有 2 分钟,而用户希望在 12:01 举行活动,则用明天的日期计算这次活动)。
- 安排一个将在不久后触发的任务(线程或其他方式),如果在 10 分钟内。
不是很确定最佳做法。应该:
- 不断检查是否有未来要做的事情,并安排短暂的任务?
- 提前生成所有时间(可能提前一个月)?
- 完全做其他事情?
还可以始终安排“下一个”事件,但担心的是,如果服务器脱机,并且错过了“下一个”事件,那么第二天永远都不会安排该事件。
澄清一下: 存储每个作业的时间和时区(例如,美国东部时间的中午)。 正在纠正夏令时,所以在计算 UTC 时间时,会以 UTC 的今天作为日期,转换为本地时间,然后用它来计算增量。正在使用 pytz 和 normalize() 来确保不会出现任何奇怪的夏令时问题。 确实有上次安排的时间和上次运行的时间,以确保不会重复执行。
查阅了以下解决方案,发现唯一其他的观察是,如果由于某种原因错过安排好的时间,“下一个”时间点永远不会发生,因为那时它已经是过去的事情了。可以编写一个第二个函数来修复任何错过的闹铃。
经过对以下答案的理解,提出了以下不那么糟糕的方案:
有以下字段:
- 上次执行事件的时间
- 上次安排事件的时间
- 下次执行事件的时间
- 时间和时区
无论何时更新事件或触发事件,都要计算并设置 next_run_time。它执行以下操作:
- 如果有上次运行时间,则计算 next_run_time,至少在未来 2 小时后(通过增加一些缓冲时间来避免夏令时问题)。
- 如果该事件从未运行过,则至少安排在未来 15 分钟后(避免同时安排多个事件)。
安排的作业执行以下操作:
- 检查所有在未来 15 分钟内有 next_run_time 并且当前未安排的事件。安排所有匹配的事件。
作业安排:
- 安排任务,并将作业设置为“现在”已安排。
当任务执行(成功)时:
- last_run_time 更新为“现在”。
- next_run_time 重新计算。
如果任务失败:
- 将作业重新安排在 30 秒后。如果超过阈值(在我的案例中是延迟 3 分钟),则中止任务并为第二天重新计算 next_run_time。这会记录下来,希望不要发生太多次。
这似乎基本上可行,因为每天都会有事件安排,这样可以腾出一些时间来避免一些棘手的问题。