[Rails] Mechanizeがファイルディスクリプタを大量に消費してしまう


内容はタイトル通り。
Railsにて、Mysql2のConnectionError出てる場合とか
ファイルディスクリプタを異常に使いまくってる場合はもしかしたら関係あるかも。

経緯

とあるサービス(Rails,puma)にて

Mysql2::Error::ConnectionError

が多発してサービスが利用できなくなる障害が発生しました。

詳しくログを追ってみると他にも

Errno::EMFILE (Too many open files @ rb_sysopen ...(略)

のようなエラーも発生している様子。

さらに、、、

# ファイルディスクリプタ上限確認
ulimit -n
# pumaプロセスのファイルディスクリプタ確認
for i in $(ps aux | grep "[p]uma" | awk '{print $2}'); do sudo ls /proc/$i/fd | wc -l; done

上記コマンドでプロセスの開いてるファイル数を確認してみたら
どうやらファイルディスクリプタがいっぱいになっているようだった。

原因

実は、ファイルを開いているわけではなくてアプリケーションで使用していた Mechanize というgemにて
外部からデータを取得する際にコネクションを作成していた様子。
(スクレイピングとかするときに使われてるgemらしい。)

ファイルディスクリプタでは、ファイルだけでなくコネクションもカウントされるようで
大量のコネクションが削除されずに作成され続けたことで問題が発生した。
(Mysqlも多分コネクション関係?? 詳しい人コメントお願いします。)

対応

単純に、コネクションが開いたままになっていることが問題。
閉じてあげる必要がある。

Mechanizeのコネクションは以下のメソッドを呼び出すと閉じてくれるらしいので
使用中のコネクションの最後の処理が終わったあたりで呼び出してあげる。

Mechanize.shutdown

あとは、サーバー再起動などで既存コネクションを消してあげましょう。