Help us understand the problem. What is going on with this article?

Node-RED: joinノードでタイムアウト処理

More than 1 year has passed since last update.

はじめに

Node-REDで通信をする際のタイムアウト処理は、ユーザディレクトリ(~/.node-red)のsetting.jsで変更することができます。例えば、httpリクエストのタイムアウトは、httpRequestTimeoutで変更できます。

しかし、全体の処理時間に制限がある場合など、呼び出し先などによって変更したい場合は対応できません。オーソドックスな方法はファンクションノードで頑張ることかもしれませんが、それではデバッグノードで簡単にデバッグするというNode-REDらしい開発ができません。そこで、標準ノードであるjoinノードを使って、呼び出しの際のタイムアウトを処理する方法を考えてみました。

joinノード

joinノードはsplitノードと組み合わされることが多く、配列などをsplitノードで分割し、それぞれを非同期に処理した後にjoinノードでまとめるという使い方をされます。実はjoinノードは単体でも利用可能で、複数のmsgオブジェクトをタイムアウト時間内にまとめて出力することができます。これを利用するわけです。

具体的には、httpリクエストの直前でmsgオブジェクトをリクエスト処理用とタイムアウト処理用に作成して利用します。joinノードでは、まとめる単位ごとに共通のidが必要で、これにはmsg._msgidを使っています。また、総数のcount、それぞれのmsgオブジェクトを識別するindexが必要です。

joinノードでは結合対象のプロパティ以外には破壊的ですので、結合対象のプロパティに保存しておきたいデータをコピーしておきます。

フロー

実際のフローが下記になります。テスト用サーバーがあるので複雑に見えますが、主要な処理は上部の7つほどのノードだけです。
image.png
ポイントは、joinの前に必要なプロパティをセットすることです。また、タイムアウトの際にはチェック用のメッセージが流れた後でhttpのレスポンスが返ってきますのでこれを捨てる必要があることです。

上部のcatchノードはタイムアウトの際に例外が発生するのでつけていますが、この辺はお好みで変更してください。

注意点

更新処理の場合、クライアント側でタイムアウトしてもサーバで処理が行われる可能性がありますので注意してください。

コード

下記をインポート(読み込み)して使ってください。
[{"id":"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":[]}]

sakaba37
阪井誠:さかば、博士(工学) • ソフトウェアプロセス、チケット駆動開発(TiDD)、 アジャイル開発に興味を持つ「プロセスプログラマー」 • 仕事とコミュニティに刺激を受ける。 <スライドシェア> http://www.slideshare.net/makotosakai <Twitter>@sakaba37
http://sakaba.cocolog-nifty.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした