В моем приложении Rails user
может создавать до 3000 invoices
в месяц. Для каждого счета он / она может также генерировать счет PDF. Это происходит на лету, то есть PDF-файлы никогда не сохраняются нигде на сервере.
Я бы хотел, чтобы мои пользователи имели возможность загружать все PDF-файлы своих счетов в виде одного ZIP-файла .
В моем текущем решении я использую PDF креветок и ZIP-хитрости трюков :
class InvoicesController < ApplicationController
def index
invoices = current_user.invoices
respond_to do |format|
format.zip do
DownloadInvoiceArchive.call(invoices, response, view_context)
end
end
end
end
class DownloadInvoiceArchive
include ActionController::Live
LIMIT = 100
def self.call(invoices, response, view_context)
zipname = "invoices.zip"
disposition = "attachment; filename=\"#{zipname}\""
response.headers["Content-Disposition"] = disposition
response.headers["Content-Type"] = "application/zip"
response.headers["Last-Modified"] = Time.now.httpdate.to_s
response.headers["X-Accel-Buffering"] = "no"
writer = ZipTricks::BlockWrite.new do |chunk|
response.stream.write(chunk)
end
ZipTricks::Streamer.open(writer) do |zip|
invoices.each_with_index do |invoice, index|
break if index == LIMIT
file_name = "#{invoice.number}.pdf"
zip.write_deflated_file(file_name) do |file_writer|
pdf = InvoicePdf.new(invoice, view_context)
file_writer << pdf.render
end
end
end
response.stream.close
end
end
Однако производительность этого подхода довольно плохая, потому что для итерации тысяч счетов и создания PDF для каждого требуется вечность. (Генерация одного PDF создает как минимум 5 SQL запросов в одиночку.)
Поэтому мой вопрос заключается в том, как повысить производительность здесь.
Один из вариантов может состоять в том, чтобы запустить генерацию PDF в фоновое задание, а затем по электронной почте ссылку для загрузки пользователю, когда он будет готов. Но где тогда должен храниться ZIP-файл? В файловой системе сервера или на Amazon S3? Данные являются строго конфиденциальными и должны быть удалены после загрузки.
Так что будет лучшим подходом здесь? Спасибо за любые указатели.