0

I'm getting an error when rendering PDFs with Grover gem in a rails app:

Grover::JavaScript::TimeoutError: Timed out after waiting 30000ms

Couple key points:

  1. Using Grover gem on rails 7 app
  2. Fails in multiple areas grover is used, so points to grover issue or rails integration issue
  3. When setting grover config to debug: true, the problem seems to go away
  4. Issue on local development server and on Heroku production
  5. The same exact code will execute properly, rendering the PDF on some requests within a second or two (seemingly pointing to random erroring, race condition, etc.)
  6. When it hangs/times out, it does so indefinitely, increasing the timeout doesn't help

I've experimented with wait_until and other options on Grover, to no avail.

Mailer calling code...

  def send_invoice_to_email(emails, invoice_id)
    @invoice = Invoice.find(invoice_id)
    @company = @invoice.company

    html = ApplicationController.render(
      template: '/invoices/pdf',
      formats: :html,
      layout: 'pdf',
      assigns: {
        invoice: @invoice,
        company: @company
      }
    )
    pdf = Grover.new(
      html,
      format: 'A4',
      wait_until: 'domcontentloaded'
    )
    attachments[attachment_name(@invoice)] = pdf.to_pdf

    subject = "Invoice #%s" % [invoice_id]
    mail(to: emails, subject: subject, tag: 'INVOICE_SEND')
  end

Here is the failing test trace...

  2) InvoiceMailer Send invoice to email names attachment appropriately
 Failure/Error: attachments[attachment_name(@invoice)] = pdf.to_pdf

 Grover::JavaScript::TimeoutError:
   Timed out after waiting 30000ms
 # /usr/share/rvm/gems/ruby-3.3.6/gems/grover-1.2.1/lib/grover/processor.rb:93:in `call_js_method'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/grover-1.2.1/lib/grover/processor.rb:20:in `convert'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/grover-1.2.1/lib/grover.rb:51:in `to_pdf'
 # ./app/mailers/invoice_mailer.rb:24:in `send_invoice_to_email'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionpack-7.2.2/lib/abstract_controller/base.rb:226:in `process_action'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionpack-7.2.2/lib/abstract_controller/callbacks.rb:261:in `block in process_action'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/activesupport-7.2.2/lib/active_support/callbacks.rb:121:in `block in run_callbacks'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actiontext-7.2.2/lib/action_text/rendering.rb:25:in `with_renderer'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actiontext-7.2.2/lib/action_text/engine.rb:71:in `block (4 levels) in <class:Engine>'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/activesupport-7.2.2/lib/active_support/callbacks.rb:130:in `instance_exec'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/activesupport-7.2.2/lib/active_support/callbacks.rb:130:in `block in run_callbacks'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/activesupport-7.2.2/lib/active_support/callbacks.rb:141:in `run_callbacks'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionpack-7.2.2/lib/abstract_controller/callbacks.rb:260:in `process_action'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionpack-7.2.2/lib/abstract_controller/base.rb:163:in `process'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionmailer-7.2.2/lib/action_mailer/rescuable.rb:29:in `block in process'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionmailer-7.2.2/lib/action_mailer/rescuable.rb:21:in `handle_exceptions'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionmailer-7.2.2/lib/action_mailer/rescuable.rb:28:in `process'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionview-7.2.2/lib/action_view/rendering.rb:40:in `process'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionmailer-7.2.2/lib/action_mailer/base.rb:657:in `block in process'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/activesupport-7.2.2/lib/active_support/notifications.rb:210:in `block in instrument'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/activesupport-7.2.2/lib/active_support/notifications/instrumenter.rb:58:in `instrument'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/activesupport-7.2.2/lib/active_support/notifications.rb:210:in `instrument'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionmailer-7.2.2/lib/action_mailer/base.rb:656:in `process'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionmailer-7.2.2/lib/action_mailer/message_delivery.rb:136:in `block in processed_mailer'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionmailer-7.2.2/lib/action_mailer/message_delivery.rb:135:in `processed_mailer'
 # /usr/share/rvm/gems/ruby-3.3.6/gems/actionmailer-7.2.2/lib/action_mailer/message_delivery.rb:32:in `__getobj__'
 # ./spec/mailers/invoice_mailer_spec.rb:29:in `block (3 levels) in <top (required)>'

Templates...

PDF HTML Layout

<!doctype html>
<html>
  <head>
    <title>
      <%= content_for?(:title) ? yield(:title) : "PCI APP - PDF" %>
    </title>
    <meta charset='utf-8' />
    <%= stylesheet_link_tag "application_pdf" %>
  </head>
  <body style="background-color: #fff">
    <div id="content">
      <%= yield %>
    </div>
  </body>
</html>

Invoice PDF HTML template

<div id="invoice-pdf">

  <div style="padding: 20px; background-color: #fff">
    <%= image_tag 'logo_with_text_gray_inc.png', style: "margin-right: 10px; max-width: 300px;" %>
    <h1 class="text-muted float-end">Invoice</h1>
  </div>

  <hr>

  <div class="invoice p-3">
    <div class="invoice__header">

      <div class="invoice__meta-container">
        <div class="invoice__date float-end">
            <%= render partial: "invoices/invoice_meta", formats: :html %>
        </div>
        <div class="invoice__remit">
          <%= render partial: "invoices/remit_to", formats: :html %>
        </div>
        <%= render partial: "invoices/invoice_to", formats: :html, locals: {address: @billing_address} %>
      </div>
    </div>
    <div class="invoice__body">
      <hr>

      <div>
        <%= @invoice.notes&.html_safe %>
      </div>

        <%= render partial: "invoices/invoice_table", formats: :html %>
    </div>

    <p>
        Accepted payment methods: <b>Check, ACH, Wire Transfer, Bitcoin</b>.
    </p>
    <p>
      <b>We appreciate your business!</b>
    </p>
  </div> <!-- invoice -->

</div> <!-- #invoice-pdf -->

How can I fix the Javascript Timeout error?

7
  • Which line points to this ./app/mailers/invoice_mailer.rb:24:in `send_invoice_to_email' ? Commented Jul 23 at 20:10
  • It's the "to_pdf" call: attachments[attachment_name(@invoice)] = pdf.to_pdf Commented Jul 23 at 20:38
  • What does your template look like? Commented Jul 23 at 20:43
  • @engineersmnky I edited the question to show some templates. Pretty standard, I believe. Commented Jul 23 at 20:47
  • Do you have any CDN for JS? Commented Jul 24 at 18:09

1 Answer 1

0

A configuration mistake was leading to the error. The documentation points out that display_url is required, and mine was nil causing issues. My brain didn't connect this dot because of the random nature of the error.

Anyhow, adding display_url in the Grover configuration seems to have fixed the random timeout issues. I suppose the display_url being nil maybe triggered some sort of race condition.

Note that the full host name is important including http(s)://

/config/initializers/grover.rb

    display_url: Rails.configuration.x.grover.base_url,

/config/enviornments/[env].rb

  config.x.grover.base_url = "http://localhost:3000"
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.