LoginSignup
2
3

More than 5 years have passed since last update.

handle leakやらかした件

Posted at

Connectionはちゃんと閉じよう(いましめ)

経緯

別のサーバーにアクセスして情報をとってくるnodejsが EMFILE, too many open files を発してプロセス死亡多発。
OSはWindowsで特にファイルも開いてないし上限ないはずなんだが...と困惑する俺氏。
なにやらハンドルが増えすぎてエラーが出ているっぽいことに気がついたあたりで
コネクション張りすぎとサーバー管理者から怒られて事態を把握。

標準的なデータ取得例(Callback)

例えばMySQLから情報を取得するには下記のようにクエリーを投げて列で取得することがある。
クエリーの前に connect してその後に end する。ワカル。

connection.connect(); // <--
connection.query('SELECT * from database',(err, row)=>{
  if (err) throw err;
  row.map() // 列の処理
  connection.end(); // <--
})

データ取得例(stream)

ところがstreamになるとどこで閉じるべきかという話になる。
コールバックがない場合、コネクションを閉じ忘れて、対象のコネクションが残ったままになる。

// データ処理するStream
const cst = Transform({objectMode:true
  ,transform:function(chunk, enc, cb){
    // 処理
    cb();
})

// クエリー結果と接続
const source_stream = queryStream("SELECT * from database");
source_stream
  .pipe(cst);
// コネクション閉じてない

function queryStream(query){
  connection.connect(); // <--
  return connection.query('SELECT * from database').stream() // streamをかえす
}

callbackで渡される場合も同様

queryStreamCallback("SELECT * from database", (err, stream)=>{
  stream
    .pipe(cst);
  // ここでendすると転送完了前に閉じてしまう
});

function queryStreamCallback(query, cb){
  connection.connect(); // <--
  connection.query('SELECT * from database',(err, stream)=>{
    return cb(err, stream)
  })
}

解決方法

直接Connectionにアクセスできる上記の例なら on('finish') で開放すればいいのですが、
使い勝手を考えると隠蔽していることが多いので直接アクセスできない。
なのでStreamを渡す側が on("end")connection.end() を登録までして返すほうが安心。

const source_stream = queryStream("SELECT * from database");
source_stream
  .pipe(cst);
// 使用側はケアしなくて良い

function queryStream(query){
  connection.connect(); // <-- 
  let st = connection.query('SELECT * from database').stream() // streamをかえす

  st.on("end", ()=>{ connection.end(); }) // <-- streamが閉じたらコネクションも閉じる

return st;
}

connect しといて後は勝手に開放してくれるだなんて思ったらだめだゾ。

発見用メモ

もしかして開放忘れてる? と言うときに確認する方法
タスクマネージャのプロセス一覧にハンドル数が表示される(ない場合は列の編集でチェックを入れる)

ハンドルリークの調査方法 ~ ハンドルリークとは?

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3