Какой лучший способ загрузить ZIP-файл с большим количеством динамически генерируемых PDF-файлов? - PullRequest
0 голосов
/ 20 января 2020

В моем приложении 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? Данные являются строго конфиденциальными и должны быть удалены после загрузки.

Так что будет лучшим подходом здесь? Спасибо за любые указатели.

1 Ответ

2 голосов
/ 20 января 2020

Если он слишком длинный для обработки HTTP-запроса, вы должны переместить его в фоновое задание. Вы можете сделать это способ быстрее, сохранив сгенерированные счета на сервере, что, кстати, звучит как хорошая идея, так как счета во многих странах должны храниться в «неизменяемом» формате данных.

Если ваша БД находится на том же сервере, что и ваши счета, вероятно, это не вызовет серьезных проблем с безопасностью.

Есть ли какая-то конкретная причина, по которой вы не сохраняете их в банкоматах?

...