Heroku环境下24/7运行数据库过期记录清理任务求助
嘿,没问题!我来帮你搞定这个24/7运行的过期记录清理任务——结合你现有的RQ Worker,咱们可以用RQ Scheduler来实现定时自动执行,完美适配你的Heroku dyno环境。
具体实现步骤
1. 添加依赖
首先,把RQ Scheduler加到你的requirements.txt里,它是RQ的官方定时调度扩展:
rq>=1.15.0 rq-scheduler>=0.12.0 redis>=4.0.0 # 加上你原本的数据库依赖,比如SQLAlchemy、psycopg2-binary等
2. 修改你的worker.py文件
更新后的代码会同时启动RQ Worker和定时调度器,自动定期执行清理任务:
import os import redis from rq import Worker, Queue, Connection from rq_scheduler import Scheduler from datetime import datetime, timedelta # 👇 替换成你实际的数据库连接和模型 from your_db_module import db, YourRecordModel listen = ['high', 'default', 'low'] redis_url = os.getenv('REDISTOGO_URL', 'redis://localhost:6379/0') def clean_expired_records(): """核心清理任务:删除expiry小于当前时间戳的记录""" current_timestamp = datetime.utcnow().timestamp() # 👇 这里根据你的数据库ORM调整查询语句 expired_records = YourRecordModel.query.filter( YourRecordModel.expiry < current_timestamp ).all() # 批量删除(如果支持的话,比逐个删更高效) if expired_records: YourRecordModel.query.filter( YourRecordModel.expiry < current_timestamp ).delete() db.session.commit() print(f"✅ 清理完成:删除了 {len(expired_records)} 条过期记录 | 时间:{datetime.utcnow()}") else: print(f"ℹ️ 无过期记录需要清理 | 时间:{datetime.utcnow()}") if __name__ == '__main__': with Connection(redis.from_url(redis_url)): # 初始化队列和调度器 q = Queue() scheduler = Scheduler(connection=redis.from_url(redis_url)) # 避免重复添加定时任务(重启dyno时不会重复创建) existing_jobs = [job for job in scheduler.get_jobs() if job.func_name == clean_expired_records.__name__] if not existing_jobs: # 👇 调整执行间隔:这里设置为每5分钟执行一次(300秒) scheduler.schedule( scheduled_time=datetime.utcnow(), # 立即执行第一次 func=clean_expired_records, interval=300, # 间隔秒数,按需修改(比如3600=1小时) repeat=None, # 无限重复执行 ) print("⏰ 已启动定时清理任务:每5分钟执行一次") # 启动RQ Worker,处理其他队列任务(如果有的话) worker = Worker(list(map(Queue, listen))) worker.work()
3. 配置Heroku Dyno
确保你的Procfile里的worker条目指向修改后的脚本:
web: gunicorn your_web_app:app worker: python worker.py
然后重启你的worker dyno:
heroku restart worker
关键注意事项
- 时区一致性:一定要确保你的
expiry字段存储的是UTC时间戳,和任务里的datetime.utcnow().timestamp()保持一致,避免时区偏差导致误删或漏删。 - 数据库连接优化:如果你的数据库连接容易超时,建议在清理任务开头重新初始化连接,或者使用数据库连接池(比如SQLAlchemy的
pool_pre_ping=True)。 - Dyno持续运行:Heroku的免费dyno会自动休眠,无法实现24/7运行。如果你需要全年无休,必须使用Hobby或Professional级别的dyno。
- Redis持久化:如果用的是免费版Redis To Go,数据可能会定期被清空,导致调度任务丢失。上面的代码已经做了检查,重启dyno时会自动重新创建任务,所以不用担心,但付费版Redis会更稳定。
替代方案(如果不需要频繁清理)
如果你的清理需求间隔较长(比如每10分钟以上),也可以用Heroku官方的Scheduler插件,它可以免费触发定时任务,不需要额外的dyno:
- 安装插件:
heroku addons:create scheduler:standard - 在Heroku控制台的Scheduler页面,添加一个定时任务,执行命令:
python -c "from worker import clean_expired_records; clean_expired_records()" - 设置执行间隔(每10分钟、小时、天)
这个方案更省资源,但缺点是最小间隔只有10分钟,适合低频清理场景。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

