Я хочу сгенерировать pdf в кусках данных, которые могут генерировать некоторое (заданное) количество строк за раз, а затем обновлять pdf таким же образом, пока не будут сгенерированы все записи. Моя цель - не забирать слишком много памяти за раз и приводить к краху sh. Потому что, когда мы генерируем миллионы данных за раз, он потребляет всю память.
Посмотрите мой код ниже.
EnforcementReports::CreatePaymentPdfReportJob = Struct.new(:report_id, :page, :report_file_path) do
PAGE_SIZE = 50000
def queue_name
"create_payment_pdf_report_job_queue"
end
def enqueue(job)
job.save!
end
def perform
return unless report.present?
return if report.status == "generated"
pdf_export
end
def max_attempts
1
end
private
def helpers
@helpers ||= ApplicationController.helpers
end
def locations
@locations ||= helpers.get_locations
end
def av
@av ||= ActionView::Base.new()
end
def report_file
if report_file_path.present?
File.open(report_file_path)
else
Tempfile.new ['payment', '.pdf'], "#{Rails.root}/tmp"
end
end
def pdf_export
av.view_paths = ActionController::Base.view_paths
file1 = report_file
pdf_html = av.render :template => "admin/reports/payments/index.pdf.erb", :layout => nil, locals: { violations: payment_violations, locations: locations, users: payment_users, report: report }
pdf_html = WickedPdf.new.pdf_from_string(pdf_html)
File.write(file1.path, mode: 'ab') do |file1|
file1 << pdf_html
end
report.update(report_update_params.merge(file: file1))
#File.delete(file1) if File.exists? file1
Delayed::Job.enqueue(EnforcementReports::CreatePaymentPdfReportJob.new(report.id, page + 1, report.file.path))
end
def payment_violations
@payment_violations ||= Violations::Filter.call(violation_issued: additional_data["violation_issued"].to_i, user_locations: user_locations, time: additional_data["time"], search_by: additional_data["search_by"] , search: additional_data["search"], user_id: additional_data["user_id"], order: additional_data["order"], column: additional_data["column"] , page_size: ENV["REPORT_PAGE_SIZE"].to_i, page: 1)["violations"]
end
def user_locations
@user_locations ||= helpers.location_ids(additional_data)
end
def report
@report ||= Report.find_by(id: report_id)
end
def report_update_params
{
file_size: file_size,
status: status
}
end
def status
return "generated" if file_size >= report.rows_count.to_i
"generating"
end
def file_size
report.file_size.to_i + ENV["REPORT_PAGE_SIZE"].to_i
end
def additional_data
report.additional_data.merge(userid: report.user_id)
end
def payment_users
@payment_users ||= User.all_user
end
end