🍵
Node.jsの標準出力をパイプで渡す時の注意点
Node.jsの標準出力をパイプで受ける場合に失敗したことになります。
失敗例
console.logで出力をしていた
test.js
for (var i = 0 ; i < 10000000 ; ++i)
{
console.log("TEST");
}
node test.js > output.txt # こちらはOK
node test.js | gzip > output.txt.gz # こちらはNG
NGの場合はメモリを大量に使用してプロセスが強制停止する。
正しい実装
fs.writeSyncで1に対して出力するように修正
test.js
const fs = require('fs');
for (var i = 0 ; i < 10000000 ; ++i)
{
fs.writeSync(1, "TEST\n");
}
node test.js > output.txt # こちらはOK
node test.js | gzip > output.txt.gz # こちらもOK
原因
console.logは出力を依頼するだけであって、実際の出力は非同期で実施される。
パイプの出力先の処理がconsole.logの出力より遅れだすと一旦内部に蓄積される。
それが一定以上貯まるとメモリ不足で強制停止する。
Node.jsの標準出力をパイプで利用する場合は、fs.writeSyncの同期出力を使わなければならない。
反省
すこし考えれば当たり前のことですが、Nodeは基本的には全て非同期なので、IOが非同期であることを忘れて痛い目にあいました。
小さいデータの場合発生せず、大きなデータを処理をする場合に発生するのでテストでは発生しないが、本番になると発生しかねない危険な状況でした。
Discussion