You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. 安装插件:heroku addons:create scheduler:standard
  2. 在Heroku控制台的Scheduler页面,添加一个定时任务,执行命令:python -c "from worker import clean_expired_records; clean_expired_records()"
  3. 设置执行间隔(每10分钟、小时、天)

这个方案更省资源,但缺点是最小间隔只有10分钟,适合低频清理场景。

内容的提问来源于stack exchange,提问作者Ryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:40:26