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

如何在Heroku上自动清理Rails应用生成的临时文件及文档?

Rails临时文件(CSV/PDF/邮件相关)自动清理最佳方案

作为常年折腾Rails应用的开发者,我太懂你这种tmp文件越堆越多的烦恼了!尤其是处理CSV导入、PDF生成和邮件发送的场景,临时文件很容易失控。下面是我总结的几套靠谱方案,从内置工具到自定义逻辑都有,你可以根据自己的需求选:


1. 利用Rails内置的临时文件清理机制

Rails其实自带了清理tmp目录的rake任务,直接用就行:

  • 清理所有tmp下的过期文件:rails tmp:clear,这个命令会默认删除tmp/cache、tmp/sockets、tmp/sessions里超过24小时的内容。如果要调整过期时间,可以在config/application.rb里修改缓存配置的expires_in参数。
  • 如果只想清理特定目录(比如tmp/pdf或者tmp/csv),可以自定义rake任务:
# lib/tasks/clean_tmp.rake
namespace :tmp do
  desc "Clean custom tmp directories (pdf, csv)"
  task clean_custom: :environment do
    dirs = %w[tmp/pdf tmp/csv]
    dirs.each do |dir|
      next unless Dir.exist?(dir)
      # 删除7天前的文件,可根据需求修改时间范围
      Dir.glob("#{dir}/*").select { |f| File.mtime(f) < 7.days.ago }.each do |file|
        FileUtils.rm_r(file, force: true)
      end
    end
  end
end

运行时直接执行 rails tmp:clean_custom 即可。


2. 用定时任务自动清理(生产环境首推)

生产环境肯定不能手动跑命令,定时任务是刚需:

  • 用Whenever gem:这是Rails生态里最常用的定时任务工具,配置简单易维护。
    1. 安装并初始化:gem install whenever,然后执行 wheneverize . 生成配置文件
    2. 在config/schedule.rb里添加定时规则:
    every :day, at: '2:00 am' do # 每天凌晨2点(低峰时段)执行
      rake 'tmp:clear'
      rake 'tmp:clean_custom' # 执行刚才自定义的清理任务
    end
    
    1. 更新系统crontab:whenever --update-crontab
  • 系统级Cron:如果不想依赖gem,直接写系统crontab也可以。执行 crontab -e 编辑任务,添加:
    0 2 * * * cd /path/to/your/rails/app && bundle exec rails tmp:clear tmp:clean_custom RAILS_ENV=production
    
    意思是每天凌晨2点切换到应用目录,执行清理任务。

3. 代码层面即时清理(针对最新生成的文档)

如果不想等定时任务,希望生成的PDF/CSV在邮件发送完成后立刻删除,可以在代码里手动控制清理逻辑:

  • 发送带PDF附件的邮件示例:
class ReportMailer < ApplicationMailer
  def send_monthly_report(user)
    pdf_path = generate_user_report_pdf(user)
    attachments['monthly_report.pdf'] = File.read(pdf_path)
    mail(to: user.email, subject: "你的月度报告已生成")
    
    # 用ensure块确保即使报错也会删除文件
    ensure
      if File.exist?(pdf_path) && pdf_path.start_with?(Rails.root.join('tmp').to_s)
        File.delete(pdf_path)
      end
  end

  private
  def generate_user_report_pdf(user)
    # 生成PDF到tmp目录,用时间戳+用户ID做文件名避免冲突
    path = Rails.root.join('tmp', "report_#{user.id}_#{Time.now.to_i}.pdf")
    # 这里替换成你的PDF生成逻辑(比如WickedPdf或Prawn)
    WickedPdf.new.pdf_from_string(render_to_string('reports/monthly', layout: 'pdf'), save_to_file: path)
    path
  end
end
  • CSV导入完成后即时清理示例:
class ImportsController < ApplicationController
  def create
    csv_file = params[:import][:file]
    tmp_path = Rails.root.join('tmp', "import_#{Time.now.to_i}.csv")
    File.open(tmp_path, 'wb') { |f| f.write(csv_file.read) }
    
    # 执行CSV导入逻辑
    ImportService.new(tmp_path).process
    redirect_to imports_path, notice: "导入成功"
    
    rescue => e
      redirect_to imports_path, alert: "导入失败:#{e.message}"
    ensure
      # 无论成功失败都删除临时文件
      File.delete(tmp_path) if File.exist?(tmp_path)
  end
end

4. 最佳实践总结

  • 分类存储临时文件:把CSV、PDF、缓存文件分别放在tmp/csv、tmp/pdf、tmp/cache,这样清理时可以针对性处理,避免误删有用文件。
  • 合理设置过期策略:缓存文件可以留短一点(比如24小时);如果生成的文档不需要留存,就即时删除;如果需要备份几天,就用定时任务删除N天前的文件。
  • 不要在tmp存永久文件:tmp目录本身就是临时存储,重要文件要存到云存储(比如S3)或应用的永久存储目录,不要依赖tmp。
  • 监控tmp目录大小:可以加个简单的监控脚本,当tmp目录超过预设大小(比如10G)时触发告警,避免磁盘被占满影响应用运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:18:11