4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-12-09

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

4
2
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
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?