エンジニアになりたい

エンジニアです

Railsにおけるストリーミングによるダウンロード処理について

大容量のCSVファイルなどをRuby on Rails側からダウンロードしようとする際に、ストリーミングでやり取りをしたくなる事がある。それは、直接ダウンロードしようとするとメモリを圧迫しすぎてしまい、上手く行かないからだ。少しずつデータを受け取り、それを少しずつファイルシステムに書き込むように処理をしたい。

rubyにおけるストリーミング処理についてとても丁寧に解説している記事があった。

qiita.com

要約すると次のようになる。

  • ruby標準のWebサーバライブラリであるWEBrickではメモリにファイルを直接読み込ませてしまい上手くいかない
  • PhusionPassenger, Thin, Unicornだと完全に受信するまで待つことはなく処理が出来る

結論WEBrick以外は大丈夫という事だが、その事を知らないと厄介なことになる。

例えばローカル開発環境で動作確認をしようとしてテストを実行するとする。するとruby標準のWebサーバライブラリであるWEBrickが動作し、そのせいで本番環境(Unicornが動作する環境など)では動作するはずのコードがローカルでは動作しないという事態が起こる。ここでコードが間違っていると思い込むと、解決するまでに時間を食ってしまう。

WEBrick以外を使用している場合にストリーミングによるダウンロード処理が可能なコード例を載せる。

uri = URI('http://example.com/large_file')
Net::HTTP.start(uri.host, uri.port, use_ssl: (uri.scheme == 'https')) do |http|
  request = Net::HTTP::Get.new uri.request_uri
  http.request request do |response|
    File.open 'large_file', 'w' do |io|
      response.read_body do |chunk|
        io.write chunk
      end
    end
  end
end

ちなみに、HTTPクライアントライブラリであるFaradayでは、TODOとしてストリーミングのサポートが挙げられており、出来ない。

github.com