如何基于Heroku Scheduler实现仅在12am、12pm后各执行一次的定时任务?
解决方案:利用脚本内时间校验+临时文件标记
绝对可以实现!我之前在Heroku上处理过类似的定时任务需求,刚好能避开Scheduler的那些限制,而且完全不用数据库。下面给你具体的思路和代码示例:
核心思路
Heroku Scheduler的不确定性确实麻烦,但我们可以把「调度判断」从Scheduler转移到任务脚本内部:
- 用Heroku Scheduler的每小时执行一次任务(这样能覆盖每天的0点和12点窗口)
- 脚本启动时先做时间校验:只有当前时间是目标小时(12am/12pm)的前10分钟内,才执行实际任务
- 用临时文件标记同小时内是否已执行,避免崩溃重试导致重复运行
具体实现步骤
1. 统一时区
首先要明确你用的时区,Heroku默认是UTC,如果你的12am/12pm是本地时间,记得在脚本里转换。比如用UTC的0点对应12am,12点对应12pm,这样最省事。
2. 编写带时间校验的脚本
这里用Python举个例子,其他语言逻辑完全通用:
import datetime import os def generate_shift_tasks(): """生成班次任务的核心逻辑,替换成你的实际代码即可""" print("开始生成当前班次的任务...") # 你的任务代码写在这里 def main(): # 用UTC时间,如需本地时区可替换(比如Asia/Shanghai) now = datetime.datetime.utcnow() current_hour = now.hour current_minute = now.minute date_hour_key = now.strftime("%Y%m%d_%H") # 日期+小时的唯一标识 # 目标小时:0=12am UTC,12=12pm UTC target_hours = {0, 12} # 第一步:检查是否在目标小时的前10分钟窗口内(适配Heroku的调度误差) if current_hour not in target_hours or current_minute >= 10: print("当前时间不在目标窗口,直接退出") return # 第二步:检查是否已经执行过(用临时文件标记,避免同窗口重复执行) marker_file = f"/tmp/shift_task_{date_hour_key}" if os.path.exists(marker_file): print("本小时内已执行过任务,退出") return # 第三步:执行实际任务 generate_shift_tasks() # 创建标记文件,防止重试重复执行 with open(marker_file, "w") as f: f.write("executed") print("任务执行完成,已创建标记文件") if __name__ == "__main__": main()
为什么这个方案可行?
- 适配Heroku Scheduler的不确定性:每小时执行的任务可能在整小时后的任意时间启动,但我们给了10分钟的窗口,足够覆盖Scheduler的误差范围
- 避免重复执行:临时文件标记会在同一个dyno的重试中保留,确保同小时内只执行一次;而dyno销毁后临时文件会自动消失,不会影响第二天的任务
- 无需数据库:完全依赖时间判断和临时文件,没有外部存储依赖,符合你的需求
部署到Heroku
在Heroku后台的Scheduler里添加一个每小时执行一次的任务,命令就是运行你的脚本,比如:
python shift_task_generator.py
这样设置后,脚本每天只会在UTC的0点和12点的前10分钟内执行一次,完美符合你的要求!
内容的提问来源于stack exchange,提问作者Tinker
相关产品推荐
相关产品推荐

