我正在将我的网站移植到 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 问题。
- 我确实有一个最后安排和最后运行的时间,以确保我不会重复执行。
看看下面的解决方案,我想我唯一的其他观察结果是,如果出于某种原因我错过了预定的时间,我的“下一个”将永远不会发生,因为它已经过去了。我想我可以制作第二个功能来修复任何错过的警报。
编辑: 在摸索了下面的答案之后,我想出了以下不太糟糕的情况:
我有以下字段
- 上次事件执行时间
- 上次安排的活动
- 下一个事件执行时间
- 一天中的时间和时区
每当我:更新事件或触发事件时,我都会计算并设置 next_run_time。这将执行以下操作:
- 如果它有最后一次运行时间,则计算 next_run_time,至少在未来 2 小时(通过添加一些填充来避免 DST 问题)。
- 如果该活动从未进行过,请在未来至少安排 15 分钟(避免任何多个同时安排)
我的预定工作执行以下操作:
- 检查在接下来的 15 分钟内具有 next_run_time 且当前未安排的所有事件。安排任何匹配。
安排工作:
- 安排任务,并将作业设置为“现在”
任务执行时(成功):
- last_run_time 更新为“现在”
- next_run_time 重新计算
如果任务失败: - 该作业将在未来 30 秒后重新安排。如果失败超过阈值(在我的情况下逾期 3 分钟),任务将中止,并重新计算第二天的 next_run_time。这会被记录下来,希望不会发生太多
这似乎很有效,因为我的活动总是(每天),所以我有能力在时间里扔一些填充物并避免一些毛茸茸的问题