2017-06-09 10 views
3

RailsでPDFファイルを生成しようとしていますが、システムのCPUが最大になることがわかりました。最初は、〜2.5%から65%〜80%まで一定の期間にわたって増加し、最終的にはページ上のiframeにPDFを表示する前に最大になります。ここに私のシステム上のメモリ使用量を監視する場合、私が得るいくつかのメッセージは以下のとおりです。Wicked_PDF gemを使用してRailsでPDFを生成するときのCPU使用率が高い

Warning or critical alerts (lasts 9 entries) 
          2017-06-09 14:58:07 (0:00:04) - CRITICAL on CPU_SYSTEM (100.0) 
          2017-06-09 14:58:04 (0:00:13) - CRITICAL on CPU_USER (Min:72.8 Mean:83.3 Max:93.7) 
          2017-06-09 14:47:39 (0:00:06) - CRITICAL on CPU_USER (93.0) 
          2017-06-09 14:47:29 (0:00:04) - WARNING on CPU_SYSTEM (74.7) 
          2017-06-09 14:36:48 (0:00:04) - CRITICAL on CPU_SYSTEM (100.0) 
          2017-06-09 14:36:45 (0:00:10) - CRITICAL on CPU_IOWAIT (Min:78.6 Mean:85.7 Max:97.4) 
          2017-06-09 14:18:06 (0:00:04) - CRITICAL on CPU_SYSTEM (94.3) 
          2017-06-09 14:18:06 (0:00:07) - CRITICAL on CPU_USER (91.0) 
2017-06-09 15:01:14  2017-06-09 14:17:44 (0:00:04) - WARNING on CPU_SYSTEM (73.8) 

私は私のPDF生成にインストールしている宝石がwicked_pdf (1.0.6)wkhtmltopdf-binary-edge (0.12.4.0)です。

コントローラ/懸念/ pdf_player_reports.rb

def director_report_pdf 
    @players = Player.where(id: params["player_ids"] 

    respond_to do |format| 
    format.html 
    format.pdf do 
    render pdf: "#{params['pdf_title']}", 
     template: 'players/director_summary_report.pdf.erb', 
     layout: 'print', 
     show_as_html: params.key?('debug'), 
     window_status: 'Loading...', 
     disable_internal_links: true, 
     disable_external_links: true, 
     dpi: 75, 
     disable_javascript: true, 
     :margin => {:top => 7, :bottom => 7, :left => 6, :right => 0}, 
     encoding: 'utf8' 
    end 
end 

プレーヤー/ director_summary_report.pdf.erb

<div class="document" style="margin-top: -63px;"> 
    <% @players.each do |player| %> 
    <% reports = player.reports.order(created_at: :desc) %> 
    <% if player.is_college_player? %> 
     <%= render partial: 'college_director_report.html.erb', player: player %> 
    <% else %> 
     <%= render partial: 'pro_director_report.html.erb', player: player %> 
    <% end %> 
    <%= "<div class='page-break'></div>".html_safe %> 
    <% end %> 
</div> 

college_director_reportを次のようにし、それぞれのコードを持つプロセスがあります。 html.erb

<%= wicked_pdf_stylesheet_link_tag "application", media: "all" %> 
<%= wicked_pdf_javascript_include_tag "application" %> 
<% provide(:title, "#{player.football_name}") %> 
<% self.formats = [:html, :pdf, :css, :coffee, :scss] %> 

<style> 
    thead { display: table-row-group; page-break-inside: avoid } 
    tfoot { display: table-row-group; } 
    /*thead:before, thead:after { display: none; }*/ 
    table { page-break-inside: avoid; } 
    tr { page-break-inside: avoid; } 
    .page-break { 
     display:block; clear:both; page-break-after:always; 
    } 
    .keep-together { page-break-before: always !important; } 
    .table-striped>tbody>tr:nth-child(odd)>td, 
    tr.found{ 
     background-color:#e2e0e0 !important; 
    } 
</style> 

<div class="row"> 
    <div class="col-xs-6"> 
     <span>DIRECTOR SUMMARY</span> 
    </div> 
    <div class="col-xs-6 text-right"> 
     <%= "#{player.full_name}/#{player.school.short_name}".upcase %> 
     <h1><%= "#{player.full_name(true)} (#{player.school.code})".upcase %></h1> 
    </div> 
</div> 

<div class="row"> 
    <div class="col-xs-12"> 
    <%= render 'directors_report_player_header', player: player %> 
    <%= render 'directors_report_workouts', player: player %> 
    <%= render 'directors_report_grades', player: player %> 
    <%= render 'legacy_directors_report_contacts', player: player %> 
    </div> 
</div> 

directors_report_player_header.html.erb

<table class="table table-condensed table-bordered"> 
    <thead> 
     <tr> 
      <th>Name</th> 
      <th>School</th> 
      <th>#</th> 
      <th>Position</th> 
     </tr> 
    </thead> 
    <tbody> 
     <tr> 
      <td><%= player.full_name(true) %></td> 
      <td><%= player.school.short_name %></td> 
      <td><%= player.jersey %></td> 
      <td><%= player.position.abbreviation %></td> 
     </tr> 
    </tbody> 
</table> 

UPDATE

私は、次の使用例のPDFジェネレータを実行し、CPUの%は、以下のように限界いっぱいまで終わるものです...

enter image description here

<table class="table table-condensed"> 
    <thead> 
     <th>Number</th> 
    </thead> 
    <tbody> 
     <% (1..60000).each do |number| %> 
     <tr> 
      <td><%= number %></td> 
     </tr> 
     <% end %> 
    </tbody> 
    </table> 
+0

あなたはどこにホスティングしていますか? – jvillian

+0

@jvillian、私は内部のUbuntuサーバー上でホスティングしています。1CPU、16GBの14.04 LTSサーバーですが、最新のUbuntuデスクトップバージョンを8GBで実行している私のローカルマシンで同じ結果が得られます – daveomcd

+0

私の場合、ヘロクには暴走があった。原因はwkhtmltopdf-binaryでした。私はwkhtmltopdf-herokuに切り替えました。多分それを見て? – jvillian

答えて

2

これをコントローラに入れることは、リクエストを展開した分が他のページの他の着信要求を生成してブロックするためにかなりの時間を要するため、あまりお勧めできません。

これは2つの懸念事項に分けてください。 HTMLを生成する1つのジョブ(このコントローラになる可能性があります)。そのHTMLをPDF形式に変換するバックグラウンドタスク。

コントローラで、DelayedJobなどを使用してジョブをトリガし、完了したジョブをポーリングするページをレンダリングします。

あなたのバックグラウンドジョブでは、Webリクエスト内ではなく、HTMLをPDFにレンダリングするだけの作業に取り組んでいます。これらの線に沿って何か:あなたが持っている場合は、あなたがこれを行う場合は

class RendersReportPdf 
    def self.call player_ids 
    html = ReportsController.render :director_report_pdf, assigns: { players: Player.where(id: player_ids } 
    pdf = WickedPdf.new.pdf_from_string html  
    temp = Tempfile.new("#{Time.now.to_i}.pdf") 
    temp.write(pdf) 
    temp.close 
    temp.path 
    # Probably upload this to S3 or similar at this point 
    # Notify the user that it's now available somehow 
    end 
end 

、あなたは問題があなたのコントローラのアクション内からWickedPDFを実行していることを除外することができますが、また、あなたが作っていることを確認あなたのサイトにアップしたままになります長期実行要求。

+0

ありがとう!これであなたに戻って遅れて申し訳ありません。だから私は、2つの異なる懸念ファイルを作成する必要があると言っている:(1)HTMLを生成するため、(2)HTMLをPDFに生成するため。 2つのジョブを順番に実行するアクティブジョブを実行しますか? – daveomcd

+0

私は謝罪する - 短い休暇!はい、私はこれをまとめて1つにまとめることは、展開するとすぐに問題を引き起こすと思います。これらを分離しておくと、物事の原因となっているかどうかを確認することができます。 – stef

0

私は将来の訪問者のために私のソリューションを投稿したいと思っていましたが、@ stefのソリューションに基づいています。

コントローラ/ concern/players_controller。私は、新しいファイルに対して、ユーザーの指定したディレクトリをチェックしておくために、AJAX呼び出しを使用して、私は部分的に更新し、この方法では、RB

def generate_report_pdf 
    players = print_settings(params) 
    pdf_title = "#{params['pdf_title']} - #{Time.now.strftime("%c")}" 
    GeneratePdfJob.perform_later(players.pluck(:id), pdf_title, current_user.code, params["format"]) 
    end 

アプリ/仕事/ generate_pdf_job.rb

def perform(*args) 

    player_ids = args[0] 
    pdf_title = args[1] 
    user_code = args[2] 
    report_type = args[3] 

    generate_pdf_document(player_ids, pdf_title, user_code, report_type) 

    end 

    def generate_pdf_document(ids, pdf_title, user_code, report_type) 

    # select the proper template by the report type specified 
    case report_type 
     when "Labels" 
      html = ApplicationController.new.render_to_string(
      template: 'players/board_labels.pdf.erb', 
       locals: { player_ids: ids }, 
       margin: { top: 6, bottom: 0, left: 32, right: 32 } 
      ) 
     when "Reports" 
      # ... 
    end 
    end 

    def save_to_pdf(html, pdf_title, user_code) 

    pdf = WickedPdf.new.pdf_from_string(
          html, 
          pdf: "#{pdf_title}", 
         layout: 'print', 
     disable_internal_links: true, 
     disable_external_links: true, 
      disable_javascript: true, 
        encoding: 'utf-8' 
    ) 

    pdf_name = "#{pdf_title}.pdf" 
    pdf_dir = Rails.root.join('public','uploads','reports',"#{user_code}") 
    pdf_path = Rails.root.join(pdf_dir,pdf_name) 

    # create the folder if it doesn't exist 
    FileUtils.mkdir_p(pdf_dir) unless File.directory?(pdf_dir) 

    # create a new file 
    File.open(pdf_path,'wb') do |file| 
     file.binmode 
     file << pdf.force_encoding("UTF-8") 
    end 

    end 

ディレクトリ内のファイルを一覧表示します。私が気に入らないのは、ユーザーのファイルのテーブルリストを持たなければならないということだけです。私はちょうどそのファイルを代わりにクライアントのブラウザにダウンロードしてダウンロードさせてもらいたいですが、それをどう動かすかはまだ分かっています。

関連する問題