• V
 

エラーをハンドリングする

全てが正常に動作する場合に、正しいことを行うフローを作ることは簡単です。 一方で、上手く動作しない場合についても考慮することも重要です。

例えば、フローが外部のデータベースやAPIと連携する場合、 もしリクエストに対する応答がない時に何が起こるでしょうか。 もしくは、MQTTノードがブローカとの接続を失った時にどうなるでしょうか。

この様な事象を正しくハンドリングするために、 どの様なアプリケーションにおいてもエラーハンドリングは必要不可欠です。 エラーのハンドリングは、アプリケーションの要件によって異なるものになります。 失敗した動作を再度試したり、警告やエラーを出したりと、 アプリケーションのロジックとは別の予測されたイベントです。

Node-REDはエラーを送出するためのふたつの方法をノードに提供しています。 それは、ログにメッセージを書くか、 または、ランタイムにエラーを送出してフローがトリガーされるかです。

エラーがログに書かれるだけであれば、サイドバーのデバッグで出力されたログが確認できますが、 フローをハンドリングすることはできません。 catchできないエラーに記載のとおりです。

ランタイムに適切に送出するには、 catchできるエラーとして、エラーハンドリングのフローをトリガーします。

Node-REDのランタイムが停止してしまう3番目のエラーもあります。 ノードに含まれるバグなどにより引き起こされる uncaughtExceptionエラー は、 フロー内ではハンドリングできません。

このガイドは、それぞれの種類のエラーについて詳しく説明し、ハンドリングするための方法について示します。 予期せぬイベントをハンドリングするフローを作成するため、 ノードのStatusイベントが利用されることw確認します。

エラーロギング

ノードがエラーをログに書く際、サイドバーのデバッグに表示されます。

Error message in the Debug sidebar

サイドバーのデバッグ内のメッセージ

エラーメッセージの内容、日時、エラーを出力したノードが表示されています。 他のデバッグメッセージと同様に、ホバリングするとワークスペース内のノードがハイライトされます。 もし、カレントのビューにそのノードが無い場合は、 右上に表示されているノード名をクリックすることでワークスペース内に表示されます。

catchできるエラー

ノードがランタイムにエラーを送出した場合、 それをハンドリングするためのフローはcatchノードが使用できます。

Catch node

catchノード

catchノードがエラーをキャッチした場合は、サイドバーのデバッグには表示されません。

catchノードから送られるメッセージは、エラーを送出したノードからのメッセージとなります。 このメッセージは error プロパティを持ち、 エラーに関する情報を提供します:

{
    "topic": ...,
    "payload": ...,
    "error": {
        "message": "An error",
        "source": {
            "id": "2e25823d.fa3f7e",
            "type": "function",
            "name": "My Function",
            "count": 1
        }
    }
}

msg.error プロパティの内容は次のとおりです:

  • msg.error:
    • message - エラーメッセージ
    • source - エラーを送出したノードの情報:
      • id - 取得元のノードのid
      • type - 取得元のノードの種類
      • name - ノード名(取得元のノードに設定されている場合)
      • count - このメッセージこのノード により出力された回数。 このプロパティはメッセージスタックのループを検出するためにランタイムによって使用されます。 ループでは、メッセージは取得元のノードに戻されエラーが再度記録されます。 ランタイムはメッセージのループを9回まで許容し、他のエラーが記録されたりcatchできないエラーが発生するとループを解除します。 このプロパティを削除するとチェックを無効にできます。

ノードがエラーを送出した際にメッセージが既にmsg.errorプロパティを持っている場合は、 そのプロパティーはmsg._errorに移動されます。

デフォルトでは、catchノードはエディタの同一のタブ内の全てのノードをトリガーするよう設定されていますが、 特定のタブの特定のノードをターゲットとすて設定することもできます。

2つのcatchノードが同じタブ内にあり、それらのターゲットが同じノードの場合、 そのノードから送出されたエラーで両方のcatchノードがトリガーされます。

catchノードが全てのノードによりトリガーされるよう設定している場合、 別のcatchノードではその他のまだキャッチされていないエラーのみをトリガーするよう設定することもできます。 これにより、特定のノードをターゲットとしたエラーハンドリングのフローを作成し、 “その他すべて”のエラーをキャッチするエラーハンドラーも作成できます。

サブフロー内のエラー

サブフロー内からのエラーがロギングされた場合、 ラインタイムはサブフロー内のCatchノードでまずチェックされます。 Catchノードがなかった場合、エラーはサブフローインスタンを含むフローにでんぱします。

catchできないエラー

これは、ノードがランタイムに正しく通知することなくログに書き出すエラーです。 catchノードでハンドリングすることができません。

ノードにはエラーをハンドリングするための他の方法が 提供されているかもしれません。 たとえば、(statusノードでモニターした)ノードのステータスとなるプロパティを更新するなどです。 これは、通常通りメッセージを送信することもありますし、エラー発生を示すプロパティーが追加されているかもしれません。

ノードの作成者に、 エラーを適切にログに書き出すよう連絡をしてみるのもよいでしょう。

uncaughtException エラー

これはノードが内部エラーを適切に扱えなかったことにより発生するNode.jsのエラーです。 Node-REDランタイム全体が停止しますが、 これ以外に安全な方法がないためです。

極端に思えますが、Node.jsのドキュメント にはこう書いてあります:

Attempting to resume normally after an uncaught exception can be similar to pulling out the power cord when upgrading a computer. Nine out of ten times, nothing happens. But the tenth time, the system becomes corrupted.

典型的な例は、ノードが非同期処理のタスクを呼び出してそれが失敗する場合です。 丁寧に実装されているノードであれば、そのタスクをエラーハンドラに登録しますが、 エラーハンドラがない場合は、そのエラーはキャッチされません。

こういうエラーに直面した場合は、どのノードで発生したのか特定する必要がありissueをあげる必要があるでしょう。 非同期エラーということもあり、これは必ずしも簡単ではありません。

Node-REDのログにあるスタックトレースは、 エラーが発生したノードを特定し、非同期タスクのエラーの原因を特定するための 糸口になるかもしれません。

ステータス変更をハンドリングする

全てのエラー状態がCatchノードでキャッチできるエラーイベントを発生させるわけではありません。 例えば、接続切断されたMQTTノードはエラーを出力しませんが、 ステータスの変化をトリガーします。

Catchノードはエラーイベントをハンドリングするために利用されるのと同じく、 Statusノードもノードの状態の変化をハンドリングするために利用されます。

Statusノードから送出されたメッセージはstatusプロパティを持ち、 それはステータスとイベントをトリガーしたノードについての情報を提供します。

{
    "status": {
        "fill": "red",
        "shape": "ring",
        "text": "node-red:common.status.disconnected",
        "source": {
            "id": "27bbb5b1.d3eb3a",
            "type": "mqtt out"
        }
    }
}