search
LoginSignup
2

More than 1 year has passed since last update.

posted at

updated at

Node-REDのはまりどころと対策

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の状態を監視してください。次にキャッチノードがあれば無効にして例外が起きていないか確認してください。それで分からない場合は、特定のタイミングやデータで発生しないか、どこまで動くか、など順に切り分けていってください。

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
What you can do with signing up
2