Ruby File.exist?возвращает истину до того, как файл станет читаемым - PullRequest
0 голосов
/ 20 ноября 2018

У меня есть приложение Rails, в котором я пытаюсь передать создание большого PDF-файла фоновому процессу и позволить пользователю увидеть его, когда он будет завершен.Это многостраничный документ, объединенный с гемом comb_pdf и переданный в delayed_job.

У меня есть 3 действия: первое создает и сохраняет файл, второе вызывается повторно с короткими задержками через асинхронный запрос, чтобы проверить,файл еще существует, а третий показывает PDF в браузере.

У меня проблемы со второй частью, так как она использует File.exist?('my_file.pdf'), но она возвращает true до завершения файлаэкономии.Ссылка, которая затем отображается для просмотра PDF-файла, приводит к ошибке (ActionController :: MissingFile).Файл фактически становится доступным примерно через 10 секунд, и в этот момент ссылка работает правильно.

Я предполагаю, что файл все еще записывается в момент проверки?Как проверить, что сохранение файла завершено и файл действительно доступен для чтения?

Ответы [ 2 ]

0 голосов
/ 20 ноября 2018

Вот так (очень широко и несколько грубо), как я это делаю:

Сначала я вызываю действие post на контроллере, который вызывает фоновый процесс создания. Это действие создает ServiceRequest (модель в моем приложении) с соответствующим service_request.details и состоянием created. Затем service_request отправляется в фоновый процесс (я использую RabbitMQ). И действие возвращает service_request.id.

Внешний интерфейс начинает пинговать (через AJAX) конечную точку запроса на обслуживание (что-то вроде service_requests/:id), а действие show ServiceRequestController отправляет обратно service_request.status (вместе с другими вещами, включая service_request.results. Это цикл, пока service_request.status не является ни completed, ни failed.

Тем временем фоновый процесс создает PDF. Когда это сделано, он устанавливает service_request.status в completed. И он устанавливает service_request.results для хранения данных, необходимых внешнему интерфейсу для поиска и получения PDF. (Я храню свои PDF-файлы в AWS и ведре, так как я на Heroku.)

Когда передний конец наконец получает service_request.status completed, он использует service_request.results для извлечения и отображения PDF.

0 голосов
/ 20 ноября 2018

Вы можете записать во временный файл, а затем переименовать его, как только он закончится.Вы еще не включили свой код, но что-то вроде этого может работать для вас:

def write_and_replace(path, file, file_name, data)
  file_path = File.join(folder_path, "#{file_name}.pdf")
  temp_file_path = File.join(folder_path, "temp_#{file_name}.pdf")

  File.open(temp_file_path, 'w') { |f| f.write(data) }

  # Args: existing file, new name
  File.rename(path, file_path)
  File.rename(temp_file_path, file)
  File.delete(file_path)
end
...