Node-REDに良い意味ではまっていますが、プログラム中には悪い意味で何度かはまっています。具体的には以下の様なNode-REDに特有のバグです。
- ファンクションノードから期待するmsgオブジェクトが出力されない
- メモリー不足
- CPU不足
ファンクションノードから期待するmsgオブジェクトが出力されない
javascriptを書かなくても実装できるNode-REDはですが、ちょっと複雑な処理になるとファンクションノードにjavascriptで書いた方が簡単な場合があります。しかし、気を付けないと思い通りのmsgオブジェクトが出力されない場合があります。
returnがない
ファンクションノードを配置すると、何もしなくても「return msg;」と書かれていて、受け取ったメッセージオブジェクトを次のノードに渡すようになっています。
手打ちをしていると誤って消すことは少ないと思いますが、コピー&ペーストした際にreturnがなくなってしまうことがあります。
このバグは編集直後に動かすと気づきやすいですが、色々なノードを触っていると、デバッグノードを色々なところにつけてmsgがどこまで出ているかを確認する必要があり、結構はまります。
処理の前にreturnしてしまう
オブジェクト.非同期メソッド(params, function(err, data) {
if(err){ // an error occurred
msg.payload = "Error"
msg.err = err;
node.send(msg);
}
else { // successful response
msg.payload = "OK";
node.send(msg);
}
});
return msg;
非同期処理の前にmsgオブジェクトを返してしまいます。時間のかかる非同期メソッドや、この後のエラー処理で止まるようにしていると、処理が一切されないように見えるので、戸惑ってしまいます。
コールバックにreturn
オブジェクト.非同期メソッド(params, function(err, data) {
if(err){ // an error occurred
msg.payload = "Error"
msg.err = err;
return msg;
}
else { // successful response
msg.payload = "OK";
return msg;
}
});
コールバックメソッドのreturnは呼び出し元の非同期メソッドに返るだけです。returnを書くと次のノードにオブジェクトを渡してくれると思い込んでいると、気づきにくいバグです。
参照渡しで破壊
出力端子が複数ある場合や、出力が二股以上になって複数のノードにつながっている場合、Node-REDがmsgオブジェクトの複製(クローン)をしてくれるので、移行の処理で更新しても安全に使うことができます。
しかし、node.send(msg)(Node-RED1.0以降はnode.send(msg,false))とすると、msgオブジェクトの参照がわたります。このため、複数の処理がnode.send()されたオブジェクトを変更すると、別の処理で扱われる値を修正することになります。このバグは結構厄介で、処理のタイミングによってうまくいくことがあったり、入力を表示しようとデバッグノードを挟んでも実際と異なる値が出力されることがあります。注意深くコードを読むか、delayノードとdebugノードを挟んで確認する以外に解決策はありません(受け取ったmsgオブジェクトを渡す必要がないなら、新しいオブジェクトを渡す方法もありますが、これはこれで意外とはまります)。
メモリー不足
大規模なシステムや、大規模データを扱う場合、クラウドなど仮想環境でメモリーが少ない場合はメモリー不足でシステムの停止や再起動が生じる場合があります。
ファンアウト
上に書いたように一つのノードから複数のノードをつなぐ場合、Node-REDがオブジェクトをコピーしてくれる場合があります。線の数だけオブジェクトがコピーされるのでなるべく1対多の接続をやめてください。
デバッグノード
1対多の接続が避けられない場合の典型例は出力のないノードを使う場合です。デバッグノードはとても便利ですが、出力がないので必ず2股になりオブジェクトがコピーされ、表示用に文字列に変換しますので、使用するメモリーが2倍以上になってしまいます。
単に通過することを知りたければdelayノードを挟んだり、functionノードでステータスを表示すると良いでしょう。(参考: ファンクションノードのデバッグどうしてる?: ソフトウェアさかば)
メモリー不足が予想される場合の対処法
まずは状況を把握してください。環境に応じてメモリーの状態を監視してください。ヒープメモリの状態はnode-red-contrib-gcで確認できます。
フローの修正が可能なら、デバッグノードの線を可能な限り切ってみてください。状況が変わるならメモリー不足です。ファンアウト(複数への接続)を減らしてなるべく一筆書きにしたり、デバッグノードを減らしてください。
処理量が少ない時は問題ないのに、処理が多い場合だけメモリが不足する場合は、ガベージコレクションが追い付いていない場合があります。この場合はディレイノードで確認や改善ができます。
CPU不足
クラウドの場合、CPUを使い切って落ちてしまう場合があります。
無限ループ
Node-REDに限らず無限ループはCPUを使い切ってしまうので、要注意です。終了条件をきちんと確認してください。特にエラー時のリトライはカウントできているか、終了判定が=なので計算誤差が生じるとおかしくならないか(不等号を使うと安全です)、など注意してコードを確認してください。
キャッチノード
例外をキャッチノードで受けると処理が終了しなくなるので注意してください。単にデバッグノードをつないでいる場合でも、大量データをsplitノードで分けて非同期に処理すると、デバッグ出力を一気にしようとしてCPUが不足したことがあります。
CPU不足が予想される場合の対処法
まずは状況を把握してください。環境に応じてCPUの状態を監視してください。次にキャッチノードがあれば無効にして例外が起きていないか確認してください。それで分からない場合は、特定のタイミングやデータで発生しないか、どこまで動くか、など順に切り分けていってください。