2

ファイルのダウンロードを同時に作成しながらストリーミングする方法を誰かが知っているかどうか疑問に思っていました。

巨大な CSV エクスポートを生成していますが、現時点では、ファイルが作成されるまでに数分かかります。ブラウザが作成されると、ファイルがダウンロードされます。

これを変更して、作成中にブラウザがファイルのダウンロードを開始するようにします。このプログレス バーを見ると、ユーザーはもっと待ちたくなるでしょう。「残り時間不明」と表示されますが、データがどんどんダウンロードされていることがわかっているので焦ることはほとんどありません。

注:Railsバージョン3.0.9を使用しています

これが私のコードです:

def users_export
  File.new("users_export.csv", "w")                 # creates new file to write to
  @todays_date = Time.now.strftime("%m-%d-%Y")
  @outfile = @todays_date + ".csv"

  @users = User.select('id, login, email, last_login, created_at, updated_at')

  FasterCSV.open("users_export.csv", "w+") do |csv|
    csv << [ @todays_date ]

    csv << [ "id","login","email","last_login", "created_at", "updated_at" ]
    @users.find_each(:batch_size => 100 ) do |u|
      csv << [ u.id, u.login, u.email, u.last_login, u.created_at, u.updated_at ]
    end
  end

  send_file "users_export.csv",
    :type => 'text/csv; charset=iso-8859-1; header=present',
    :disposition => "attachment; filename=#{@outfile}",
    :stream => true,
end
4

1 に答える 1

1

私は数週間前にこの質問に対する答えを探しました。データがクライアントにストリーミングされている場合、Heroku は長時間実行されている API 呼び出しの 1 つを 30 秒後にタイムアウトしないのではないかと考えました。私は有望に見える答えさえ見つけました:

format.xml do
  self.response_body =
    lambda { |response, output|
      output.write("<?xml version='1.0' encoding='UTF-8' ?>")
      output.write("<results type='array' count='#{@report.count}'>")
      @report.each do |result|
        output.write("""
          <result>
            <element-1>Data-1</element-1>
            <element-2>Data-2</element-2>
            <element-n>Data-N</element-n>
          </result>
        """)
      end
      output.write("</results>")
    }
  end

response_body ラムダは、クライアントに戻る出力バッファに直接アクセスできるという考えです。ただし、実際には、ラックには、どのデータをいつ返送するかについて独自の考えがあります。さらに、ラムダパターンとしてのこの response_body は、レールの新しいバージョンでは非推奨であり、サポートは 3.2 で完全に削除されたと思います。ミドルウェア スタックで手を汚して、この出力をRails Metalとして書き込むこともできますが……

あえて言うなら、この作業をバックグラウンド ジョブにリファクタリングすることを強くお勧めします。利点はたくさんあります:

  • ユーザーはただ座ってダウンロードを待つ必要はありません。彼らはファイルを要求してから、サイトの他の興味深い部分をブラウズすることができます。

  • ファイルの生成とダウンロードはより堅牢になります。たとえば、現在のセットアップでダウンロードの 3 分目にユーザーがインターネット接続を一時的にでも失った場合、ユーザーはその間ずっと失われ、最初からやり直す必要があります。ファイルがサイトのバックグラウンドで生成されている場合、インターネットが必要なのは、ジョブを開始するまでの間だけです。

  • バックグラウンド ジョブがファイルを生成し、生成されたファイルへのリンクをアプリ内のページに提供すると、フロントエンド プロセスの負荷が軽減され、サイト全体の負荷が軽減される可能性があります。1 つのファイル生成で複数のダウンロードを処理できる可能性があります。

  • 実質的にすべての Rails Web サーバーはシングル スレッドであり、すぐに使用できる同期であるため、ユーザーが要求するたびに、この 1 つのファイルのダウンロードにアプリ サーバー プロセス全体が結び付けられます。これにより、ユーザーがサイトに対して誤って DoS 攻撃を実行することが容易になります。

  • バックグラウンドで生成されたファイルを S3 などの CDN に送信すると、ユーザーが目にするダウンロード速度のパフォーマンスが向上する可能性があります。

  • バックグラウンド プロセスが完了したら、電子メールでユーザーに通知できるため、ユーザーはファイル生成を開始したコンピューターにいる必要さえありません。

  • アプリケーションにバックグラウンド ジョブ システムを導入すると、電子メールの送信や検索インデックスの更新など、さらに多くの用途を見つけることができます。

申し訳ありませんが、これは元の質問に実際には答えていません。しかし、私はこれがより良い全体的な解決策であると強く信じています.

于 2012-07-03T21:25:27.210 に答える