Node-REDで通信をする際のタイムアウト処理は、ユーザディレクトリ(~/.node-red)のsetting.jsで変更することができます。例えば、httpリクエストのタイムアウトは、httpRequestTimeoutで変更できます。
しかし、全体の処理時間に制限がある場合など、呼び出し先などによって変更したい場合は対応できません。オーソドックスな方法はファンクションノードで頑張ることかもしれませんが、それではデバッグノードで簡単にデバッグするというNode-REDらしい開発ができません。そこで、標準ノードであるjoinノードを使って、呼び出しの際のタイムアウトを処理する方法を考えてみました。
joinノードはsplitノードと組み合わされることが多く、配列などをsplitノードで分割し、それぞれを非同期に処理した後にjoinノードでまとめるという使い方をされます。実はjoinノードは単体でも利用可能で、複数のmsgオブジェクトをタイムアウト時間内にまとめて出力することができます。これを利用するわけです。
具体的には、httpリクエストの直前でmsgオブジェクトをリクエスト処理用とタイムアウト処理用に作成して利用します。joinノードでは、まとめる単位ごとに共通のidが必要で、これにはmsg._msgidを使っています。また、総数のcount、それぞれのmsgオブジェクトを識別するindexが必要です。
"75ee1c7.c0e5464","type":"join","z":"967c5dd7.dee1a","name":"","mode":"custom","build":"merged","property":"data","propertyType":"msg","key":"topic","joiner":"\n","joinerType":"str","accumulate":false,"timeout":"3","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":610,"y":220,"wires":[["61b5c8ec.15b63"]]},{"id":"a63fd121.9be3","type":"debug","z":"967c5dd7.dee1a","name":"時間内","active":true,"console":false,"complete":"true","x":770,"y":260,"wires":[]},{"id":"4d768f00.8ead18","type":"function","z":"967c5dd7.dee1a","name":"チェック用msg作成","func":"let ret1 = {};\nlet ret2 = {};\nret1.id = ret2.id = msg._msgid;\n// ret1.backup = msg.payload;\nret2.data = {backup: msg.payload};\n\nreturn [ret1, ret2];","outputs":2,"noerr":0,"x":160,"y":200,"wires":[["d5f777c.c4eba88"],["b07e9ae5.b5df28"]]},{"id":"61b5c8ec.15b63","type":"function","z":"967c5dd7.dee1a","name":"タイムアウト判定","func":"if (msg.data.req && msg.data.check ) {\n return [msg.data, null]; // OK;\n}\nelse if (msg.data.check ) {\n return [null, msg.data]; // timeOut\n} // ret1.data.req のみは捨てる \n","outputs":2,"noerr":0,"x":590,"y":280,"wires":[["a63fd121.9be3"],["3e7cdc8a.0b0f14"]]},{"id":"95a03086.c8a628","type":"debug","z":"967c5dd7.dee1a","name":"タイムアウト","active":true,"console":false,"complete":"true","x":800,"y":340,"wires":[]},{"id":"acf1e79b.8e7a18","type":"function","z":"967c5dd7.dee1a","name":"Join用リクエストmsg","func":"let ret1 = {};\nret1.data = msg;\nret1.data.req = true;\nret1.count = 2;\nret1.index = 0;\nret1.id = msg.id;\nret1.complete = true;\n // ch - 文字列またはバッファの場合、メッセージを文字列またはバイトの配列として分割するために使用されるデータ\n // len - 固定長の値を使って分割したときの各メッセージの長さ\n\nreturn ret1;","outputs":1,"noerr":0,"x":420,"y":160,"wires":[["75ee1c7.c0e5464"]]},{"id":"d5f777c.c4eba88","type":"http request","z":"967c5dd7.dee1a","name":"","method":"GET","ret":"txt","url":"http://localhost:1880/test","tls":"","x":370,"y":100,"wires":[["acf1e79b.8e7a18"]]},{"id":"3e7cdc8a.0b0f14","type":"change","z":"967c5dd7.dee1a","name":"タイムアウト設定","rules":[{"t":"set","p":"statusCode","pt":"msg","to":"Timeout","tot":"str"},{"t":"set","p":"payload","pt":"msg","to":"NG","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":340,"wires":[["95a03086.c8a628"]]},{"id":"c6d5d3a3.b1ad4","type":"inject","z":"967c5dd7.dee1a","name":"タイムアウト","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":380,"wires":[["16990334.237f15"]]},{"id":"ae91ea01.fc484","type":"inject","z":"967c5dd7.dee1a","name":" 正常","topic":"","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":130,"y":420,"wires":[["67212cfb.acd604"]]},{"id":"16990334.237f15","type":"change","z":"967c5dd7.dee1a","name":"","rules":[{"t":"set","p":"timeout","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":380,"wires":[["413690a7.c84b7"]]},{"id":"7ccc98fd.be9938","type":"comment","z":"967c5dd7.dee1a","name":"テスト設定","info":"","x":100,"y":340,"wires":[]},{"id":"9e1e9675.3edc1","type":"comment","z":"967c5dd7.dee1a","name":"テストサーバー","info":"","x":120,"y":480,"wires":[]},{"id":"e4a3e329.67a9e","type":"http in","z":"967c5dd7.dee1a","name":"","url":"/test","method":"get","upload":false,"swaggerDoc":"","x":140,"y":520,"wires":[["912e543.afb19a8"]]},{"id":"912e543.afb19a8","type":"switch","z":"967c5dd7.dee1a","name":"timeout==false","property":"timeout","propertyType":"global","rules":[{"t":"false"}],"checkall":"true","repair":false,"outputs":1,"x":330,"y":520,"wires":[["8c956349.51fd8"]]},{"id":"9961a69b.3ac7d","type":"http response","z":"967c5dd7.dee1a","name":"","statusCode":"","headers":{},"x":690,"y":520,"wires":[]},{"id":"67212cfb.acd604","type":"change","z":"967c5dd7.dee1a","name":"","rules":[{"t":"set","p":"timeout","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":420,"wires":[["413690a7.c84b7"]]},{"id":"8c956349.51fd8","type":"change","z":"967c5dd7.dee1a","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"OK","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":520,"wires":[["9961a69b.3ac7d"]]},{"id":"287d1512.5e9a62","type":"inject","z":"967c5dd7.dee1a","name":"","topic":"","payload":"DATA","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":100,"wires":[["4d768f00.8ead18"]]},{"id":"b07e9ae5.b5df28","type":"function","z":"967c5dd7.dee1a","name":"join用チェックmsg","func":"msg.count = 2;\nmsg.index = 1;\nmsg.data.check = true;\n\nreturn msg;","outputs":1,"noerr":0,"x":390,"y":220,"wires":[["75ee1c7.c0e5464"]]},{"id":"413690a7.c84b7","type":"debug","z":"967c5dd7.dee1a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":530,"y":400,"wires":[]},{"id":"9fa34a45.09784","type":"catch","z":"967c5dd7.dee1a","name":"","scope":["d5f777c.c4eba88"],"x":360,"y":40,"wires":[["87b6e72b.bf2598"]]},{"id":"87b6e72b.bf2598","type":"debug","z":"967c5dd7.dee1a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"error","x":540,"y":40,"wires":[]}]