如何在ActiveJob内部将CSV文件直接写入S3存储桶?
手动上传S3实现方案
你已经通过ActiveStorage接入S3,项目默认已安装aws-sdk-s3依赖,可直接调用AWS官方客户端实现内存级操作,全程无需写入本地磁盘,完美适配Heroku文件系统限制。
核心实现逻辑
- 直接复用ActiveStorage已有的S3配置,无需额外新增配置项
- CSV生成、ZIP打包全流程使用内存流
StringIO操作,完全绕过本地文件写入 - 最终ZIP包可直接上传到S3,也可同时按原有逻辑关联到ActiveStorage附件
- 邮件发送可选择直接附加ZIP流,或生成S3临时下载链接推送
修改后的Job代码示例
def perform(company_id, recipient_id) company = Company.find(company_id) zipfile_name = "company_#{ company.id }_#{ Time.current.to_date.to_s }_archive.zip" csv_files = {} # 生成用户CSV(内存操作,不写入本地) users_file_name = "#{ company.name.parameterize.underscore }_users_list.csv" csv_files[users_file_name] = company.users.to_csv # 其他CSV生成逻辑同理,全部存入csv_files哈希即可 # ... # 内存中打包ZIP zip_buffer = Zip::OutputStream.write_buffer do |zos| csv_files.each do |file_name, csv_content| zos.put_next_entry(file_name) zos.write csv_content end end zip_buffer.rewind # ========== 手动上传到S3核心代码 ========== # 复用ActiveStorage的S3配置 s3_config = Rails.application.config.active_storage.service_configurations[:amazon] s3_client = Aws::S3::Client.new( access_key_id: s3_config[:access_key_id], secret_access_key: s3_config[:secret_access_key], region: s3_config[:region] ) # 上传ZIP到S3 s3_client.put_object( bucket: s3_config[:bucket], key: "data_exports/#{zipfile_name}", # 可自定义S3内的存储路径 body: zip_buffer, content_type: 'application/zip' ) # 如需生成S3临时下载链接,可调用以下方法,expires_in单位为秒 # download_url = s3_client.presigned_url(:get_object, bucket: s3_config[:bucket], key: "data_exports/#{zipfile_name}", expires_in: 3600 * 24 * 7) # 原有ActiveStorage关联逻辑修正(原来的写法存的是路径字符串而非文件内容,此处直接传内存流即可) zip_buffer.rewind company.data_exports.attach( io: zip_buffer, filename: zipfile_name, content_type: 'application/zip' ) # 发送邮件逻辑不变 last_id = company.data_exports.last.id CompanyMailer.mail_data_export(company.id, recipient_id, last_id).deliver_now end
注意事项
- 若数据量极大,可适当调高Heroku ActiveJob的执行超时时间,避免任务被强制终止
- 无需保留本地tmp文件写入逻辑,全内存操作执行效率更高,也完全规避Heroku文件系统限制
内容的提问来源于stack exchange,提问作者hellion
相关产品推荐
相关产品推荐

