Railsにおけるストリーミングによるダウンロード処理について
大容量のCSVファイルなどをRuby on Rails側からダウンロードしようとする際に、ストリーミングでやり取りをしたくなる事がある。それは、直接ダウンロードしようとするとメモリを圧迫しすぎてしまい、上手く行かないからだ。少しずつデータを受け取り、それを少しずつファイルシステムに書き込むように処理をしたい。
rubyにおけるストリーミング処理についてとても丁寧に解説している記事があった。
要約すると次のようになる。
- 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としてストリーミングのサポートが挙げられており、出来ない。