如何实现随Nginx启动的带故障恢复的循环定时函数?
根据你的需求——两个任务随服务启动持续运行、以上次执行结束为起点计算间隔、出错自动重启,结合你提到的技术方向,我整理了两个靠谱的方案:
方案一:Celery Beat + 自定义任务调度(推荐,适合已有Celery栈的场景)
如果你们已经在用Celery,完全不需要丢掉现有框架,只要调整任务的调度逻辑就能解决问题:
改造任务的调度方式
Celery Beat默认的crontab是固定时间触发(比如每3分钟的00秒),不符合你“以上次执行结束为起点计时”的需求。我们可以让任务自己调度下一次执行:from celery import Celery from datetime import timedelta app = Celery('tasks', broker='redis://localhost:6379/0') # 第一个任务:每5分钟执行一次(从上次结束开始算) @app.task(bind=True) def task_every_5min(self): try: # 你的任务逻辑写在这里 print("执行5分钟间隔的任务...") # 任务执行成功后,调度下一次执行 self.apply_async(countdown=5*60) except Exception as e: print(f"任务执行出错:{e}") # 出错后立即重试,或者也可以设置延迟重试,比如10秒后 self.retry(exc=e, countdown=10) # 第二个任务:每3分钟执行一次 @app.task(bind=True) def task_every_3min(self): try: print("执行3分钟间隔的任务...") self.apply_async(countdown=3*60) except Exception as e: print(f"任务执行出错:{e}") self.retry(exc=e, countdown=10)这里的核心是
apply_async(countdown=间隔秒数)——任务执行完成后,立刻安排下一次在N秒后启动,完全符合“上次结束后计时”的要求;而self.retry则处理了出错自动重启的需求。用进程管理工具确保随服务启动
用Supervisor或者Systemd来管理Celery Worker进程,配置开机自启:- 比如用Supervisor,配置文件示例:
[program:celery_worker] command=celery -A your_project worker --loglevel=info directory=/path/to/your/project user=your_user autostart=true autorestart=true startretries=3 stdout_logfile=/var/log/celery/worker.log stderr_logfile=/var/log/celery/worker_err.log
这样只要服务器启动,Celery Worker就会自动启动,而任务第一次执行可以在应用启动时手动触发一次(或者写个启动脚本调用
task_every_5min.delay()和task_every_3min.delay())。- 比如用Supervisor,配置文件示例:
方案二:Supervisor + 独立脚本(轻量,适合不想用Celery的场景)
如果觉得Celery太重,直接写两个独立的Python脚本,配合Supervisor管理进程更简单:
编写带间隔逻辑的任务脚本
比如第一个脚本task_5min.py:import time import traceback def run_task(): # 你的任务逻辑 print("执行5分钟间隔的任务...") if __name__ == "__main__": while True: try: run_task() # 任务执行成功后,休眠5分钟 time.sleep(5*60) except Exception as e: print(f"任务出错:{e}") traceback.print_exc() # 出错后可以选择立即重试,或者休眠10秒再试 time.sleep(10)第二个脚本
task_3min.py同理,把休眠时间改成3*60秒。这里的逻辑很直接:执行任务→成功就等N分钟→失败就短暂等待后重试,完全满足“上次结束后计时”的要求。用Supervisor管理脚本进程
给每个脚本写一个Supervisor配置,确保它们随服务器启动,崩溃后自动重启:[program:task_5min] command=python3 /path/to/task_5min.py directory=/path/to/scripts user=your_user autostart=true autorestart=true startretries=5 stdout_logfile=/var/log/tasks/task_5min.log stderr_logfile=/var/log/tasks/task_5min_err.log [program:task_3min] command=python3 /path/to/task_3min.py directory=/path/to/scripts user=your_user autostart=true autorestart=true startretries=5 stdout_logfile=/var/log/tasks/task_3min.log stderr_logfile=/var/log/tasks/task_3min_err.log配置好后,重启Supervisor,这两个脚本就会自动启动,并且永远保持运行状态,出错也会自动重试/重启。
关于Cron+Supervisor的说明
Cron的特点是固定时间点触发(比如每3分钟的00秒),没法做到“以上次任务结束为起点计时”——如果某次任务执行了2分钟,那下一次Cron触发就会和上次结束只间隔1分钟,不符合你的需求。除非你在脚本里加锁,确保同一时间只有一个任务实例在运行,但这样间隔还是固定的,不是从结束开始算。所以这个方案不太适合你的核心需求,不推荐。
内容的提问来源于stack exchange,提问作者user10898133

