Crontab重复启动任务实例而非单个实例的问题排查与解决
问题描述
我有一个需要每5分钟运行的Python脚本,通过activate.sh脚本调用:
#!/bin/bash ../../env/bin/python3 ./run.py
对应的crontab定时任务配置如下:
*/5 * * * * cd /var/www/usa/api/BackgroundTasks && /bin/bash ./activate.sh
该配置在3台服务器中的2台运行正常,每次仅启动单个任务实例,但美国服务器会生成多个run.py实例,甚至耗尽服务器内存引发性能问题。以下是核心业务代码app.py:
import time, sys, os, datetime try: sys.path.append("../") from Flabstraction.Flabstraction import Pysqlalchemy, MailingService from Flabstraction.constants import constants_dict from AutomatedReports import schedules_builder_2 from DeleteOldJobs import delete_old_jobs from StallTimers import stop_timers constants_selector = "LOCAL" path_to_self = os.getcwd() selectors = ['/au/','/eu/','/nz/','/usa/','/demo/'] for sel in selectors: if sel in path_to_self: constants_selector = sel.upper().replace('/', '') break constants = constants_dict[constants_selector] mail = MailingService() sql = Pysqlalchemy('mysql+pymysql', constants["mysql_user"], constants["mysql_pw"], constants["server_ip"], constants["mysql_db"]) file = open('./background.log', 'w') file.write(str(datetime.datetime.now()) + " : running started. \n") if constants_selector in ["LOCAL", "US"]: schedules_builder_2(sql, constants["timezone"], constants_selector, mail, constants) if constants_selector in ["AU", "NZ", "EU"]: delete_old_jobs(sql, constants["timezone"]) stop_timers(sql, constants["timezone"], constants["_instance_id"]) file.write(str(datetime.datetime.now()) + " : running stapped. \n") file.close() except Exception as e: file = open("./background.log", "w") file.write("Error occured: ", e) file.close() raise e
请问该问题仅出现在一台服务器的原因是什么?如何解决?
可能原因
- 任务执行超时:美国服务器对应的
constants_selector为US,会执行schedules_builder_2函数,而其他正常服务器执行的是delete_old_jobs。如果US服务器上该任务的数据量更大、逻辑更复杂,导致单次执行时间超过5分钟,下一次cron触发时前一个进程还未结束,就会产生多个实例。 - 脚本异常处理错误:代码中异常块的
file.write("Error occured: ", e)存在语法错误(write不支持多参数传入),会触发新的TypeError,导致原异常未被正确捕获处理,进程可能异常退出但未清理资源,后续cron仍会启动新进程。 - 缺少进程互斥机制:其他服务器任务执行速度快,未暴露问题,但US服务器任务耗时久,脚本和cron配置中没有任何互斥锁机制,无法阻止cron在任务未完成时启动新实例。
- 服务器环境差异:美国服务器可能存在系统负载过高、磁盘IO缓慢、数据库响应延迟等情况,导致脚本执行被阻塞,进而超时。
解决办法
添加进程互斥锁
- 修改crontab命令,使用
flock确保同一时间只有一个实例运行:*/5 * * * * cd /var/www/usa/api/BackgroundTasks && flock -n ./task.lock /bin/bash ./activate.sh - 或者在Python脚本中添加进程检查逻辑,比如创建临时PID文件,启动时判断PID文件是否存在且对应进程存活,避免重复启动。
- 修改crontab命令,使用
修复异常处理错误
将异常块中的错误代码修改为:file.write(f"Error occured: {str(e)}\n")避免因语法错误导致的二次异常,确保异常信息能正确写入日志,便于排查问题。
优化
schedules_builder_2任务性能- 分析该函数的执行逻辑,检查是否存在慢查询、循环冗余等问题,针对性优化(比如给数据库添加索引、批量处理数据、异步执行非核心逻辑)。
- 如果任务确实无法在5分钟内完成,调整cron的执行间隔,或者拆分任务为多个子任务分散执行。
排查服务器环境问题
- 查看美国服务器的系统日志、cron日志(通常在
/var/log/cron或/var/log/syslog),确认是否有cron重复触发、系统资源不足的情况。 - 监控脚本执行时的CPU、内存、磁盘IO和数据库响应时间,定位性能瓶颈。
- 查看美国服务器的系统日志、cron日志(通常在
内容的提问来源于stack exchange,提问作者Dimitar
相关产品推荐
相关产品推荐

