diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb index 9e75900b8d..c9893f7bbb 100644 --- a/app/controllers/admin/reports_controller.rb +++ b/app/controllers/admin/reports_controller.rb @@ -57,8 +57,9 @@ module Admin def render_report_as(format) if OpenFoodNetwork::FeatureToggle.enabled?(:background_reports, spree_current_user) + blob = ReportJob.create_blob! job = ReportJob.perform_later( - report_class, spree_current_user, params, format + report_class, spree_current_user, params, format, blob ) Timeout.timeout(max_wait_time) do sleep 1 until job.done? diff --git a/app/jobs/report_job.rb b/app/jobs/report_job.rb index 6c27c3ac28..9844b376be 100644 --- a/app/jobs/report_job.rb +++ b/app/jobs/report_job.rb @@ -1,15 +1,29 @@ # frozen_string_literal: true -# Renders a report and saves it to a temporary file. +# Renders a report and stores it in a given blob. class ReportJob < ApplicationJob - def perform(report_class, user, params, format) + def self.create_blob! + # ActiveStorage discourages modifying a blob later but we need a blob + # before we know anything about the report file. It enables us to use the + # same blob in the controller to read the result. + ActiveStorage::Blob.create_before_direct_upload!( + filename: "tbd", + byte_size: 0, + checksum: "0", + content_type: "application/octet-stream", + ).tap do |blob| + ActiveStorage::PurgeJob.set(wait: 1.month).perform_later(blob) + end + end + + def perform(report_class, user, params, format, blob) report = report_class.new(user, params, render: true) result = report.render_as(format) - write(result) + write(result, blob) end def done? - @done ||= File.file?(filename) + @done ||= blob.reload.checksum != "0" end def result @@ -18,17 +32,17 @@ class ReportJob < ApplicationJob private - def write(result) - File.write(filename, result, mode: "wb") + def write(result, blob) + io = StringIO.new(result) + blob.upload(io, identify: false) + blob.save! end def read_result - File.read(filename) - ensure - File.unlink(filename) + blob.download end - def filename - Rails.root.join("tmp/report-#{job_id}") + def blob + arguments[4] end end diff --git a/spec/jobs/report_job_spec.rb b/spec/jobs/report_job_spec.rb index 99d3153f08..897b0f2fc7 100644 --- a/spec/jobs/report_job_spec.rb +++ b/spec/jobs/report_job_spec.rb @@ -3,12 +3,13 @@ require 'spec_helper' describe ReportJob do - let(:report_args) { [report_class, user, params, format] } + let(:report_args) { [report_class, user, params, format, blob] } let(:report_class) { Reporting::Reports::UsersAndEnterprises::Base } let(:user) { enterprise.owner } let(:enterprise) { create(:enterprise) } let(:params) { {} } let(:format) { :csv } + let(:blob) { ReportJob.create_blob! } it "generates a report" do job = perform_enqueued_jobs(only: ReportJob) do