Search code examples
ruby-on-railsrubypdfdelayed-job

Ruby File.exist? returns true before file is readable


I've got a Rails app where I'm trying to pass the creation of a large PDF to a background process and allow the user to see it when it's finished. It's a multi-page document combined with the combine_pdf gem and passed to delayed_job.

I have 3 actions: the first creates and saves the file, the second is called repeatedly with short delays via an asynchronous request to check if the file exists yet, and the third shows the PDF in the browser.

I'm having trouble with the second part, as it uses File.exist?('my_file.pdf'), but this is returning true before the file has finished saving. The link that is then shown to view the PDF results in an error (ActionController::MissingFile). The file actually becomes available about 10 seconds later, at which point the link works correctly.

I'm guessing the file is still being written at the point that it's checked? How can I check the file saving has completed and the file is actually available to be read?


Solution

  • This is (very broadly and somewhat roughly) how I do it:

    First, I call a post action on the controller that is calling the background create process. This action creates a ServiceRequest (a model in my app) with relevant service_request.details and a status of created. The service_request is then sent to the background process (I use RabbitMQ). And the action returns the service_request.id.

    The front end starts pinging (via AJAX) the service request end point (something like service_requests/:id), and the ServiceRequestController's show action sends back the service_request.status (along with other stuff, including service_request.results. This loops while the service_request.status is neither completed nor failed.

    Meanwhile, the background process creates the PDF. When it is done, it sets the service_request.status to completed. And, it sets service_request.results to contain the data the front end needs to locate and retrieve the PDF. (I store my PDFs to and AWS bucket since I'm on Heroku.)

    When the front end finally receives a service_request.status of completed it uses the service_request.results to fetch and display the PDF.