水津です。

Node-REDでメッセージの待ち合わせをしたいと思ったことはありませんか??
でも単純にワイヤーを結合しても待ち合わせできず、行うにはちょっとしたテクニックが必要になります。
今回は、Node-REDのフローにて待ち合わせを行う方法と、それを簡単に実現する自作ノードについて紹介したいと思います。

まずはフローを単純に結合してみる

  • シナリオ:
    並列で実行された2つのfunctionノードを単純に結合し、それぞれのfunctionにて設定された値の合計値を計算する

  • 期待結果:
    それぞれのfunctionにて設定した値「4」「3」の合計値である「7」が出力されること

    検証フロー
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-46-16

    functionノード「2つのpayloadの合計算出」

    msg.payload = msg.payload + msg.payload;
    
    return msg;
    

    誰もが一度はやるパターンかと思います。でもこれ、うまくいかないんですよね、、、。非同期実行されてしまい、期待する結果は出力されません。
    結果
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-46-37

    この原因は以下だと考えられます。

  • メッセージを待つノードが一体何個のメッセージを待てばいいのかキチンと定義されていないこと
  • 先に到着したメッセージを保持(一時的に保管)できていないこと

    次はこれらを解消してみたいと思います。

    Global変数に待ち合わせ情報を持たせてみる

    先ほどのフローをちょっとカスタマイズし、以下のようにしました。

  • シナリオ:
    並列で実行された2つのfunctionノードを結合しその情報を単純にGlobal変数にて管理、2メッセージ分到着後に値の合計値を計算する

  • 期待結果:
    それぞれのfunctionにて設定した値「4」「3」の合計値である「7」が出力されること

    検証フロー
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-47-00

    以下のように「並列数=2」のFunctionノードにて並列実行数を定義、「2つのpayloadの合計算出」のFunctionノードにて並列数分のメッセージの待ち合わせを行っています。

    functionノード「並列数=2」

    context.global.n = 2;
    context.global.data = new Array(2);
    
    return msg;
    

    functionノード「2つのpayloadの合計算出」

    // 入力数を減らす
    context.global.n--;
    
    // msg.payloadのデータを格納
    context.global.data[context.global.n] = msg.payload;
    
    // 定義した入力数が来たら、集計処理を行い、msg.payloadを返す
    if (context.global.n === 0) {
        // msg.payloadの合計値を算出
        var sum = 0;
        for (var i = 0; i < context.global.data.length; i++) {
            sum += context.global.data[i];
        }
        msg.payload = sum;
    
        return msg;
    }
    

    このフローを実行するとどんな結果が得られるでしょうか?
    結果
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-47-14

    おっ!期待する結果が出力されました。待ち合わせはうまくいったようです。では次に、多重実行時を検証してみたいと思います。

    先ほどの処理を多重実行してみる

    先ほどのフローを3多重で実行するようにちょっとフローを書き換え実行してみました。

  • シナリオ:
    並列で実行された2つのfunctionノードを結合しその情報を単純にGlobal変数にて管理、2メッセージ分到着後に値の合計値を計算する。
    これを3多重で同時実行する。

  • 期待結果:
    それぞれのfunctionにて設定した値「4」「3」の合計値である「7」が同時実行数である3回出力されること

    検証フロー
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-48-11

    結果
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-48-22

    うーん、、、「7」が3つ出力されるのが期待した結果だったのですが、「6」が1つだけ出力されました。
    この原因は以下だと考えられます。

  • 処理がメッセージの到着順に行われること
  • 多重実行したメッセージごとに処理ができるよう制御できていないこと(Global変数を単純に使っているので、変数汚染が発生していること)

    次はこれらを解消してみたいと思います。

    Global変数をメッセージ結合したい組み合わせごとに隔離してみる

    見た目は先程のフローと変えずに、「並列数=2」と「2つのpayloadの合計算出」のFunctionノードの処理を少し変えました。

  • シナリオ:
    並列で実行された2つのfunctionノードを結合しその情報をメッセージ結合したい組み合わせごとにGlobal変数にて管理、2メッセージ分到着後に値の合計値を計算する。
    これを3多重で同時実行する。

  • 期待結果:
    それぞれのfunctionにて設定した値「4」「3」の合計値である「7」が同時実行数である3回出力されること

    検証フロー
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-48-47

    Functionノードは以下のように書き換えました。

    functionノード「並列数=2」

    if (context.global.aggr === null) {
        context.global.aggr = {};
    }
    
    var uuid = (function(){
        var S4 = function() {
            return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
        };  
        return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4() +S4());
    })();
    
    var aggrObj =  {
        "n" : 2,
        "data" : new Array(2)
    };
    
    context.global.aggr[uuid] = aggrObj;
    
    msg.process =  {
        "uuid" :  uuid
    };
    
    return msg;
    

    functionノード「2つのpayloadの合計算出」

    // 入力数を減らす
    context.global.aggr[msg.process.uuid].n--;
    
    // msg.payloadのデータを格納
    context.global.aggr[msg.process.uuid].data[context.global.aggr[msg.process.uuid].n] = msg.payload;
    
    // 定義した入力数が来たら、集計処理を行い、msg.payloadを返す
    if (context.global.aggr[msg.process.uuid].n === 0) {
        // msg.payloadの合計値を算出
        var sum = 0;
        for (var i = 0; i < context.global.aggr[msg.process.uuid].data.length; i++) {
            sum += context.global.aggr[msg.process.uuid].data[i];
        }
        delete context.global.aggr[msg.process.uuid];
        msg.payload = sum;
    
        return msg;
    }
    

    結果はどうでしょうか!?
    結果
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-48-59

    うまくいきました!!
    このように、多重実行されるメッセージごとに到着待ちを行い処理ができるように実装することで、Aggregator Patternにも対応できることがわかりました。
    でも、毎回こんなの実装するのメンドウですよね?そこで、自作ノードの出番です!!

    node-red-contrib-message-aggregatorを使ってみる

  • シナリオ:
    Aggregaterノードを使用し、メッセージ結合したい組み合わせごとに値の合計値を計算する。
    これを3多重で同時実行する。

  • 期待結果:
    それぞれのfunctionにて設定した値「4」「3」の合計値である「7」が同時実行数である3回出力されること

    利用するためにまずはNode-REDアプリケーションにこのNodeを追加する必要があります。以下手順で追加してください。
    1. BluemixのNode-REDより、Starter codeをダウンロードする

    1. DLしたアーカイブ内にあるpackage.jsonを開き、dependenciesに以下エントリーを追加し保存する
      "node-red-contrib-message-aggregator":"0.0.x"
      
    2. Bluemix Runtimeにpushする
      cf push <Application Name>
      
    3. Node-REDのWeb画面を開き、Node一覧のfunctionセクション内に、Aggregator Nodeが追加されたことを確認する

    追加されましたでしょうか? では、使っていきましょう!

    できること、使い方
    メッセージの待ち合わせが出来る自作ノード「node-red-contrib-message-aggregator」ですが、「Global変数を実行ごとにUUIDで隔離してみる」の「2つのpayloadの合計算出」と似たようなことができるように実装したものとなります。
    ノードの設定は簡単で、このノードで待ち合わせるメッセージの数を設定するだけです。(2つ待ち合わせするなら「2」を設定するだけ)あとは、待ち合わせる組み合わせを区別するために、このノードへの入力メッセージのmsg.CorrelIdに、待ち合わせる組み合わせを識別するIDを設定するればOKです。
    出力は、入力されたそれぞれのmsg.payloadが、出力のmsg.payloadに配列でセットされ出力されます。

    先ほどのフローをカスタマイズする
    以下のようにカスタマイズしました。
    検証フロー
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-49-21

    変更したノードは以下のように設定してます。

    functionノード「CorrelId発行」

    var uuid = (function(){
        var S4 = function() {
            return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
        };  
        return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4() +S4());
    })();
    
    
    msg.CorrelId = uuid;
    
    return msg;
    

    Aggregatorノード「Aggregator」
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-49-51

    functionノード「合計算出」

    var result = {
        'a' : msg.payload[0].a + msg.payload[1].a,
        'b' : msg.payload[0].b + msg.payload[1].b
    };
    
    msg.payload = result;
    
    return msg;
    

    では、実行してみましょう!!
    Aggregater直後の出力は以下になります。
    中間出力結果
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-51-14

    最終出力は以下となります。
    結果
    %e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-12-13-49-33

    うまくいきました!!

    まとめ

    いかがでしたでしょうか??
    ちょっとメンドウなメッセージの待ち合わせ(Aggregator Pattern)についても「node-red-contrib-message-aggregator」を使うことでカンタンに実現することができます。ぜひご利用くださいませ。

    node-red-contrib-message-aggregator:
    https://www.npmjs.com/package/node-red-contrib-message-aggregator

    検証用フローのソース

    [{"id":"39d800a0.c628","type":"comment","z":"d9b2b329.264d5","name":"Global変数を用いて結合 多重実行した場合","info":"","x":209.75,"y":1205.3214282989502,"wires":[]},{"id":"7580030a.8a7ffc","type":"function","z":"d9b2b329.264d5","name":"payload=4","func":"msg.payload = 4;\n\nreturn msg;","outputs":1,"noerr":0,"x":467.2976379394531,"y":1398.5001277923584,"wires":[["2cb61687.d349ea"]]},{"id":"ed6a41bc.1295c","type":"function","z":"d9b2b329.264d5","name":"2つのpayloadの合計算出","func":"// 入力数を減らす\ncontext.global.n--;\n\n// msg.payloadのデータを格納\ncontext.global.data[context.global.n] = msg.payload;\n\n// 定義した入力数が来たら、集計処理を行い、msg.payloadを返す\nif (context.global.n === 0) {\n    // msg.payloadの合計値を算出\n    var sum = 0;\n    for (var i = 0; i < context.global.data.length; i++) {\n        sum += context.global.data[i];\n    }\n    msg.payload = sum;\n\n    return msg;\n}","outputs":1,"noerr":0,"x":839.6905670166016,"y":1418.32155418396,"wires":[["ecb322e0.134ce"]]},{"id":"1986fb62.e67905","type":"function","z":"d9b2b329.264d5","name":"payload=3","func":"msg.payload = 3;\n\nreturn msg;","outputs":1,"noerr":0,"x":468.2976379394531,"y":1438.5001430511475,"wires":[["f1acaaa0.0e5358"]]},{"id":"ecb322e0.134ce","type":"debug","z":"d9b2b329.264d5","name":"7を出力","active":true,"console":"false","complete":"payload","x":1034.119125366211,"y":1418.321545124054,"wires":[]},{"id":"e518ed.ff1ae71","type":"function","z":"d9b2b329.264d5","name":"並列数=2","func":"context.global.n = 2;\ncontext.global.data = new Array(2);\n\nreturn msg;","outputs":1,"noerr":0,"x":263.7976417541504,"y":1417.2501430511475,"wires":[["7580030a.8a7ffc","1986fb62.e67905"]]},{"id":"f7d6460c.0829b8","type":"comment","z":"d9b2b329.264d5","name":"↓1つ目の値","info":"","x":467.0441589355469,"y":1360.0741939544678,"wires":[]},{"id":"1ccc8309.e3337d","type":"inject","z":"d9b2b329.264d5","name":"2値の和を求める計算実行","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":175.88934326171875,"y":1240.7646675109863,"wires":[["5e7bba33.a18444","5cf45b6e.a30ba4","5b23b555.a4dc4c"]]},{"id":"76952b08.896ad4","type":"comment","z":"d9b2b329.264d5","name":"↑2つ目の値","info":"","x":467.8774719238281,"y":1477.0741176605225,"wires":[]},{"id":"9529afd9.6ad65","type":"comment","z":"d9b2b329.264d5","name":"グローバル変数に並列数を定義","info":"","x":223.23456954956055,"y":1457.7644262313843,"wires":[]},{"id":"af247e46.50db8","type":"comment","z":"d9b2b329.264d5","name":"↑並列数分の入力が来た後、和を計算","info":"","x":883.0561370849609,"y":1461.0146145820618,"wires":[]},{"id":"2cb61687.d349ea","type":"delay","z":"d9b2b329.264d5","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"milliseconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":631.9643249511719,"y":1398.000005722046,"wires":[["ed6a41bc.1295c"]]},{"id":"f1acaaa0.0e5358","type":"delay","z":"d9b2b329.264d5","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"milliseconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":631.9643249511719,"y":1439.000005722046,"wires":[["ed6a41bc.1295c"]]},{"id":"5e7bba33.a18444","type":"function","z":"d9b2b329.264d5","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":365.75000381469727,"y":1242.250020980835,"wires":[["e518ed.ff1ae71"]]},{"id":"5cf45b6e.a30ba4","type":"function","z":"d9b2b329.264d5","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":365.75001335144043,"y":1279.392876625061,"wires":[["e518ed.ff1ae71"]]},{"id":"5b23b555.a4dc4c","type":"function","z":"d9b2b329.264d5","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":365.7500190734863,"y":1316.5356721878052,"wires":[["e518ed.ff1ae71"]]},{"id":"102e68d9.efd197","type":"comment","z":"d9b2b329.264d5","name":"Global変数+UUIDを用いて結合 多重実行した場合","info":"","x":225.0357208251953,"y":1551.7142572402954,"wires":[]},{"id":"d3e086bd.2c1f78","type":"function","z":"d9b2b329.264d5","name":"payload=4","func":"msg.payload = 4;\n\nreturn msg;","outputs":1,"noerr":0,"x":463.83332443237305,"y":1754.8929805755615,"wires":[["d1970cb7.2e68f"]]},{"id":"c5a5d12c.3a5a3","type":"function","z":"d9b2b329.264d5","name":"2つのpayloadの合計算出","func":"// 入力数を減らす\ncontext.global.aggr[msg.process.uuid].n--;\n\n// msg.payloadのデータを格納\ncontext.global.aggr[msg.process.uuid].data[context.global.aggr[msg.process.uuid].n] = msg.payload;\n\n// 定義した入力数が来たら、集計処理を行い、msg.payloadを返す\nif (context.global.aggr[msg.process.uuid].n === 0) {\n    // msg.payloadの合計値を算出\n    var sum = 0;\n    for (var i = 0; i < context.global.aggr[msg.process.uuid].data.length; i++) {\n        sum += context.global.aggr[msg.process.uuid].data[i];\n    }\n    delete context.global.aggr[msg.process.uuid];\n    msg.payload = sum;\n\n    return msg;\n}","outputs":1,"noerr":0,"x":841.2262077331543,"y":1775.9644842147827,"wires":[["6e66384f.9199c8"]]},{"id":"d5ba941d.2a4568","type":"function","z":"d9b2b329.264d5","name":"payload=3","func":"msg.payload = 3;\n\nreturn msg;","outputs":1,"noerr":0,"x":464.83332443237305,"y":1794.8929958343506,"wires":[["1a1d8928.e5e277"]]},{"id":"6e66384f.9199c8","type":"debug","z":"d9b2b329.264d5","name":"7を出力","active":true,"console":"false","complete":"payload","x":1035.6547660827637,"y":1775.9644751548767,"wires":[]},{"id":"80fe094a.7f01f8","type":"function","z":"d9b2b329.264d5","name":"並列数=2","func":"if (context.global.aggr === null) {\n    context.global.aggr = {};\n}\n\nvar uuid = (function(){\n    var S4 = function() {\n        return (((1+Math.random())*0x10000)|0).toString(16).substring(1);\n    };  \n    return (S4()+S4()+\"-\"+S4()+\"-\"+S4()+\"-\"+S4()+\"-\"+S4()+S4() +S4());\n})();\n\nvar aggrObj =  {\n    \"n\" : 2,\n    \"data\" : new Array(2)\n};\n\ncontext.global.aggr[uuid] = aggrObj;\n\nmsg.process =  {\n    \"uuid\" :  uuid\n};\n\nreturn msg;","outputs":1,"noerr":0,"x":260.33331298828125,"y":1777.3929510116577,"wires":[["d3e086bd.2c1f78","d5ba941d.2a4568"]]},{"id":"d2f7252c.2d08d8","type":"comment","z":"d9b2b329.264d5","name":"↓1つ目の値","info":"","x":463.5798454284668,"y":1716.467046737671,"wires":[]},{"id":"c1d09c51.3e2f6","type":"inject","z":"d9b2b329.264d5","name":"2値の和を求める計算実行","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":169.92505645751953,"y":1589.6574935913086,"wires":[["33054c3a.ccfab4","576e1ace.a891e4","7d705a05.828fa4"]]},{"id":"fac6277b.0539d8","type":"comment","z":"d9b2b329.264d5","name":"↑2つ目の値","info":"","x":464.41315841674805,"y":1833.4669704437256,"wires":[]},{"id":"80b687ec.7f4978","type":"comment","z":"d9b2b329.264d5","name":"グローバル変数に並列数を定義","info":"","x":227.27024841308594,"y":1812.9072341918945,"wires":[]},{"id":"61dd95c8.9e226c","type":"comment","z":"d9b2b329.264d5","name":"↑並列数分の入力が来た後、和を計算","info":"","x":884.5917778015137,"y":1818.6575446128845,"wires":[]},{"id":"d1970cb7.2e68f","type":"delay","z":"d9b2b329.264d5","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"milliseconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":628.5000114440918,"y":1754.392858505249,"wires":[["c5a5d12c.3a5a3"]]},{"id":"1a1d8928.e5e277","type":"delay","z":"d9b2b329.264d5","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"milliseconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":628.5000114440918,"y":1795.392858505249,"wires":[["c5a5d12c.3a5a3"]]},{"id":"33054c3a.ccfab4","type":"function","z":"d9b2b329.264d5","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":362.2857093811035,"y":1589.892827987671,"wires":[["80fe094a.7f01f8"]]},{"id":"576e1ace.a891e4","type":"function","z":"d9b2b329.264d5","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":362.2857189178467,"y":1627.035683631897,"wires":[["80fe094a.7f01f8"]]},{"id":"7d705a05.828fa4","type":"function","z":"d9b2b329.264d5","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":362.2857246398926,"y":1664.178479194641,"wires":[["80fe094a.7f01f8"]]},{"id":"f43670bf.0bc99","type":"comment","z":"d9b2b329.264d5","name":"Aggregatorノードを使用し結合 多重実行した場合","info":"","x":217.35714721679688,"y":41.00000047683716,"wires":[]},{"id":"7f209b9d.80df64","type":"function","z":"d9b2b329.264d5","name":"payload.a=4, payload.b=asdfg","func":"msg.payload = {\n    'a' : 4,\n    'b' : \"asdfg\"\n};\n\n\nreturn msg;","outputs":1,"noerr":0,"x":478.65479278564453,"y":210.4287748336792,"wires":[["201576af.dfea8a"]]},{"id":"291ec224.d6e13e","type":"function","z":"d9b2b329.264d5","name":"payload.a=3, payload.b=qazxsw","func":"msg.payload = {\n    'a' : 3,\n    'b' : \"qazxsw\"\n};\n\n\nreturn msg;","outputs":1,"noerr":0,"x":478.40479278564453,"y":247.92877578735352,"wires":[["60af09d9.9f50f8"]]},{"id":"78c42e46.873bd","type":"function","z":"d9b2b329.264d5","name":"CorrelId発行","func":"\nvar uuid = (function(){\n    var S4 = function() {\n        return (((1+Math.random())*0x10000)|0).toString(16).substring(1);\n    };  \n    return (S4()+S4()+\"-\"+S4()+\"-\"+S4()+\"-\"+S4()+\"-\"+S4()+S4() +S4());\n})();\n\n\nmsg.CorrelId = uuid;\n\nreturn msg;","outputs":1,"noerr":0,"x":230.15479278564453,"y":229.92871475219727,"wires":[["7f209b9d.80df64","291ec224.d6e13e"]]},{"id":"39413d4a.c6bec2","type":"comment","z":"d9b2b329.264d5","name":"↑並列処理","info":"","x":407.98462677001953,"y":284.0028123855591,"wires":[]},{"id":"39a562b.fc65a9e","type":"comment","z":"d9b2b329.264d5","name":"←3多重。同時実行時の動作確認用","info":"","x":577.0916900634766,"y":115.94299697875977,"wires":[]},{"id":"201576af.dfea8a","type":"delay","z":"d9b2b329.264d5","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"milliseconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":702.0714797973633,"y":209.9286527633667,"wires":[["3ad4ccfb.c52b34"]]},{"id":"60af09d9.9f50f8","type":"delay","z":"d9b2b329.264d5","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"milliseconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":702.071475982666,"y":248.42865371704102,"wires":[["3ad4ccfb.c52b34"]]},{"id":"5488544c.ab77ac","type":"function","z":"d9b2b329.264d5","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":350.35718154907227,"y":78.42859745025635,"wires":[["78c42e46.873bd"]]},{"id":"f3839c71.0c7c6","type":"function","z":"d9b2b329.264d5","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":350.35719108581543,"y":115.57145309448242,"wires":[["78c42e46.873bd"]]},{"id":"2f2cd7dd.d0d328","type":"function","z":"d9b2b329.264d5","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":350.3571968078613,"y":152.71424865722656,"wires":[["78c42e46.873bd"]]},{"id":"99c4eb63.663b18","type":"debug","z":"d9b2b329.264d5","name":"","active":true,"console":"false","complete":"true","x":1027.357192993164,"y":190.82153511047363,"wires":[]},{"id":"4710415e.b8efc","type":"comment","z":"d9b2b329.264d5","name":"↑結合用のキーを発行","info":"","x":228.25,"y":267.0713996887207,"wires":[]},{"id":"e41b3008.1be4d","type":"comment","z":"d9b2b329.264d5","name":"↓動作確認のため次ノードへの着信をずらす","info":"","x":799.5000152587891,"y":173.32141494750977,"wires":[]},{"id":"b6e0fd1b.491f","type":"comment","z":"d9b2b329.264d5","name":"↑結合","info":"","x":855.7500152587891,"y":263.3214168548584,"wires":[]},{"id":"3ad4ccfb.c52b34","type":"Aggregator","z":"d9b2b329.264d5","name":"","aggregations":2,"x":874.7499923706055,"y":228.8214054107666,"wires":[["99c4eb63.663b18","7ce52155.831ae"]]},{"id":"a7533c43.58acc","type":"inject","z":"d9b2b329.264d5","name":"2値の和を求める計算実行","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":161.25000762939453,"y":77.50000953674316,"wires":[["5488544c.ab77ac","f3839c71.0c7c6","2f2cd7dd.d0d328"]]},{"id":"bd7ceb6a.428318","type":"comment","z":"d9b2b329.264d5","name":"←3多重。同時実行時の動作確認用","info":"","x":596.25,"y":1285,"wires":[]},{"id":"2a20ecfd.d5df14","type":"comment","z":"d9b2b329.264d5","name":"←3多重。同時実行時の動作確認用","info":"","x":591.25,"y":1632.5,"wires":[]},{"id":"55d4469e.aa2bb8","type":"comment","z":"d9b2b329.264d5","name":"↓動作確認のため次ノードへの着信をずらす","info":"","x":728.75,"y":1355,"wires":[]},{"id":"549b8f0.fab647","type":"comment","z":"d9b2b329.264d5","name":"↓動作確認のため次ノードへの着信をずらす","info":"","x":727.5,"y":1716.25,"wires":[]},{"id":"7ce52155.831ae","type":"function","z":"d9b2b329.264d5","name":"合計算出","func":"var result = {\n    'a' : msg.payload[0].a + msg.payload[1].a,\n    'b' : msg.payload[0].b + msg.payload[1].b\n};\n\nmsg.payload = result;\n\n\nreturn msg;","outputs":1,"noerr":0,"x":1036.875015258789,"y":228.75000381469727,"wires":[["622fba46.9dd044"]]},{"id":"622fba46.9dd044","type":"debug","z":"d9b2b329.264d5","name":"a=7, b=asdfgqazxsw を出力","active":false,"console":"false","complete":"payload","x":1240.625015258789,"y":228.75000381469727,"wires":[]},{"id":"5d5059d6.a2afa8","type":"comment","z":"d9b2b329.264d5","name":"Global変数を用いて結合した場合","info":"","x":167.5,"y":1047.5000133514404,"wires":[]},{"id":"5a30aecd.a5cf5","type":"function","z":"d9b2b329.264d5","name":"payload=4","func":"msg.payload = 4;\n\nreturn msg;","outputs":1,"noerr":0,"x":568.7976379394531,"y":1068.1787252426147,"wires":[["3a17e51e.c5e81a"]]},{"id":"9585a7a.f6a7a58","type":"function","z":"d9b2b329.264d5","name":"2つのpayloadの合計算出","func":"// 入力数を減らす\ncontext.global.n--;\n\n// msg.payloadのデータを格納\ncontext.global.data[context.global.n] = msg.payload;\n\n// 定義した入力数が来たら、集計処理を行い、msg.payloadを返す\nif (context.global.n === 0) {\n    // msg.payloadの合計値を算出\n    var sum = 0;\n    for (var i = 0; i < context.global.data.length; i++) {\n        sum += context.global.data[i];\n    }\n    msg.payload = sum;\n\n    return msg;\n}","outputs":1,"noerr":0,"x":941.1905670166016,"y":1088.0001516342163,"wires":[["865d7d3d.79a28"]]},{"id":"be5d641c.41a298","type":"function","z":"d9b2b329.264d5","name":"payload=3","func":"msg.payload = 3;\n\nreturn msg;","outputs":1,"noerr":0,"x":569.7976379394531,"y":1108.1787405014038,"wires":[["88a8eafe.775718"]]},{"id":"865d7d3d.79a28","type":"debug","z":"d9b2b329.264d5","name":"7を出力","active":true,"console":"false","complete":"payload","x":1135.619125366211,"y":1088.0001425743103,"wires":[]},{"id":"25dbc27a.da243e","type":"function","z":"d9b2b329.264d5","name":"並列数=2","func":"context.global.n = 2;\ncontext.global.data = new Array(2);\n\nreturn msg;","outputs":1,"noerr":0,"x":365.2976417541504,"y":1086.9287405014038,"wires":[["5a30aecd.a5cf5","be5d641c.41a298"]]},{"id":"90f42472.6f0bd8","type":"comment","z":"d9b2b329.264d5","name":"↓1つ目の値","info":"","x":568.5441589355469,"y":1029.7527914047241,"wires":[]},{"id":"83e0b3fd.7c1f5","type":"inject","z":"d9b2b329.264d5","name":"2値の和を求める計算実行","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":172.38934326171875,"y":1086.693223953247,"wires":[["25dbc27a.da243e"]]},{"id":"974c5ae6.68b3a8","type":"comment","z":"d9b2b329.264d5","name":"↑2つ目の値","info":"","x":569.3774719238281,"y":1146.7527151107788,"wires":[]},{"id":"d581c938.2a7e38","type":"comment","z":"d9b2b329.264d5","name":"グローバル変数に並列数を定義","info":"","x":324.73456954956055,"y":1127.4430236816406,"wires":[]},{"id":"1955d0a5.e6aa2f","type":"comment","z":"d9b2b329.264d5","name":"↑並列数分の入力が来た後、和を計算","info":"","x":984.5561370849609,"y":1130.6932120323181,"wires":[]},{"id":"3a17e51e.c5e81a","type":"delay","z":"d9b2b329.264d5","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"milliseconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":733.4643249511719,"y":1067.6786031723022,"wires":[["9585a7a.f6a7a58"]]},{"id":"88a8eafe.775718","type":"delay","z":"d9b2b329.264d5","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"milliseconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":733.4643249511719,"y":1108.6786031723022,"wires":[["9585a7a.f6a7a58"]]},{"id":"77cee197.88312","type":"comment","z":"d9b2b329.264d5","name":"↓動作確認のため次ノードへの着信をずらす","info":"","x":830.25,"y":1024.6785974502563,"wires":[]},{"id":"b61a0c9e.49e5f","type":"comment","z":"d9b2b329.264d5","name":"フローを単純に結合した場合","info":"","x":155,"y":818.7500114440918,"wires":[]},{"id":"973b5788.68c4a8","type":"function","z":"d9b2b329.264d5","name":"payload=4","func":"msg.payload = 4;\n\nreturn msg;","outputs":1,"noerr":0,"x":393.79764556884766,"y":859.4287533760071,"wires":[["b232232a.4dcde"]]},{"id":"79609031.869f7","type":"function","z":"d9b2b329.264d5","name":"2つのpayloadの合計算出","func":"\nmsg.payload = msg.payload + msg.payload;\n\nreturn msg;","outputs":1,"noerr":0,"x":766.1905746459961,"y":879.2501797676086,"wires":[["c929b718.36d648"]]},{"id":"2b6a0287.d495fe","type":"function","z":"d9b2b329.264d5","name":"payload=3","func":"msg.payload = 3;\n\nreturn msg;","outputs":1,"noerr":0,"x":394.79764556884766,"y":899.4287686347961,"wires":[["9bfadaed.640528"]]},{"id":"c929b718.36d648","type":"debug","z":"d9b2b329.264d5","name":"7を出力","active":true,"console":"false","complete":"payload","x":960.6191329956055,"y":879.2501707077026,"wires":[]},{"id":"e2a0959a.1d5f68","type":"comment","z":"d9b2b329.264d5","name":"↓1つ目の値","info":"","x":393.5441665649414,"y":821.0028195381165,"wires":[]},{"id":"4eecc6ef.b11338","type":"inject","z":"d9b2b329.264d5","name":"2値の和を求める計算実行","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"x":172.38934326171875,"y":859.1932506561279,"wires":[["973b5788.68c4a8","2b6a0287.d495fe"]]},{"id":"cf2dfa2a.30d208","type":"comment","z":"d9b2b329.264d5","name":"↑2つ目の値","info":"","x":394.37747955322266,"y":938.0027432441711,"wires":[]},{"id":"1d99eb94.e26614","type":"comment","z":"d9b2b329.264d5","name":"↑並列数分の入力が来た後、和を計算","info":"","x":809.5561447143555,"y":921.9432401657104,"wires":[]},{"id":"b232232a.4dcde","type":"delay","z":"d9b2b329.264d5","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"milliseconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":558.4643325805664,"y":858.9286313056946,"wires":[["79609031.869f7"]]},{"id":"9bfadaed.640528","type":"delay","z":"d9b2b329.264d5","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"milliseconds","rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":558.4643325805664,"y":899.9286313056946,"wires":[["79609031.869f7"]]},{"id":"efb89fa2.10476","type":"comment","z":"d9b2b329.264d5","name":"↓動作確認のため次ノードへの着信をずらす","info":"","x":655.2500076293945,"y":815.9286255836487,"wires":[]}]