🍵

Node.jsの標準出力をパイプで渡す時の注意点

2022/05/19に公開

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