Poll2Push Converter and example with Openwhisk

The flow inserts a subflow named Poll2PushConverter, in order to simplify the process of polling towards an endpoint that does not support blocking calls up to completion. The initial call returns after a specified period and is then fed to the Poll2PushConverter in order to undertake the polling. Upon successful completion (or reaching of max number of attempts), the subflow triggers a message to one of the respective outputs. poll2pushsubflow

An example flow is also included with relation to how to apply it to an Openwhisk web action invocation that defaults to 65 seconds of waiting time in the initial blocking call, while the action takes longer to complete. poll2pushexampleflow

The docker image of the used action can be found here and is a delay action that takes as inputs the iterations and the delay of each iteration: https://hub.docker.com/r/gkousiou/noderedaction

the flow for which can be found here https://flows.nodered.org/flow/f0795ad9f25ad2affcadb8deb305fdf3/in/VOf-0UrN5e2j

In the flow it is assumed that it has been registered with the following options: wsk action create dockeraction --docker gkousiou/noderedaction --web true

[{"id":"a669fa3740561e95","type":"subflow","name":"PollTOPushConverter","info":"This helper node aims at performing synchronous calls for polling in case of an async API (calls that return prior to completion, e.g. in the case of non blocking calls in OW, the initial request is returned with a submission success and an activation id in order to follow up on the result).\n\nIn this case, the node does polling to a specific endpoint in order to detect whether the function has successfully finished\n\nThe node has three outputs:\n - Output 1 indicates successful finalization of the API call\n - Output 2 indicates intermediate failure and was added to return the reason for failure\n - Output 3 indicates final failure after max attempts\n\nCurrently the node assumes that in case of failure we get a >=40X return code, but this may not always be the case.\n\nThe node can be configured for the URL (msg.url), the HTTP method (msg.method), the maximum attempts (msg.maxAttempts), polling period (msg.pollPeriod), the status code above which to retry (msg.retryCode) and the status code for deciding the final success (msg.acceptCode). The msg properties override the UI set properties.\n\nGiven that conditions upon which the initial call needs to be polled are highly dependent on the used API, the node assumes that the initial call has been performed a priori.\n\nCredentials for accessing the HTTP endpoint need to be set within the http request node of the subflow.\n \n","category":"PHYSICS Helpers","in":[{"x":60,"y":160,"wires":[{"id":"e83bccc0e0065888"}]}],"out":[{"x":780,"y":140,"wires":[{"id":"bc62ca0fab4a2ec3","port":0}]},{"x":780,"y":260,"wires":[{"id":"3d57ac6bbaeda35d","port":0}]},{"x":780,"y":360,"wires":[{"id":"3d57ac6bbaeda35d","port":1}]}],"env":[{"name":"maxAttempts","type":"str","value":"3","ui":{"label":{"en-US":"max Attempts"}}},{"name":"pollPeriod","type":"str","value":"3000","ui":{"label":{"en-US":"Polling Period (ms)"}}},{"name":"method","type":"str","value":"","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"GET"},"v":"GET"},{"l":{"en-US":"POST"},"v":"POST"},{"l":{"en-US":"PUT"},"v":"PUT"},{"l":{"en-US":"DELETE"},"v":"DELETE"}]}}},{"name":"url","type":"str","value":"http://10.100.59.182:3233/api/v1/namespaces/_/activations/","ui":{"label":{"en-US":"Status URL"}}},{"name":"retryCode","type":"num","value":"202","ui":{"label":{"en-US":"Retry Code >="}}},{"name":"acceptCode","type":"num","value":"200","ui":{"label":{"en-US":"Accept Code <="}}}],"meta":{},"color":"#C7E9C0"},{"id":"e83bccc0e0065888","type":"function","z":"a669fa3740561e95","name":"defaults","func":"\nif (msg.hasOwnProperty('maxAttempts')){\n    msg.iterations=msg.maxAttempts;\n} else {\n    msg.iterations=env.get('maxAttempts');\n}\n    \nif (msg.hasOwnProperty('pollPeriod')){\n    \n} else {\n    msg.pollPeriod=env.get('pollPeriod');\n}\n\nif (msg.hasOwnProperty('method')){\n    \n} else {\n    msg.method=env.get('method');\n}\n\nif (msg.hasOwnProperty('url')){\n    \n} else {\n    msg.url=env.get('url');\n}\n\nif (msg.hasOwnProperty('retryCode')){\n    \n} else {\n    msg.retryCode=env.get('retryCode');\n}\n\nif (msg.hasOwnProperty('acceptCode')){\n    \n} else {\n    msg.acceptCode=env.get('acceptCode');\n}\n\nmsg.delay=msg.pollPeriod;\nmsg.start=Date.now();\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":200,"y":160,"wires":[["aa58b3514de9ea77"]]},{"id":"5c38f8323ffca468","type":"function","z":"a669fa3740561e95","name":"iterations--","func":"msg.iterations=msg.iterations-1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":300,"wires":[["3d57ac6bbaeda35d"]]},{"id":"3d57ac6bbaeda35d","type":"switch","z":"a669fa3740561e95","name":"if iterations finished","property":"iterations","propertyType":"msg","rules":[{"t":"gte","v":"1","vt":"num"},{"t":"lt","v":"1","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":550,"y":300,"wires":[["aa58b3514de9ea77"],[]]},{"id":"3fc50a1725f897bf","type":"comment","z":"a669fa3740561e95","name":"SUCCESS","info":"","x":880,"y":140,"wires":[]},{"id":"87abf007da989f36","type":"comment","z":"a669fa3740561e95","name":"FINAL FAIL","info":"","x":890,"y":360,"wires":[]},{"id":"785188d617170876","type":"delay","z":"a669fa3740561e95","name":"delay","pauseType":"delayv","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"x":170,"y":300,"wires":[["5c38f8323ffca468"]]},{"id":"aa58b3514de9ea77","type":"http request","z":"a669fa3740561e95","name":"","method":"use","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"basic","x":410,"y":160,"wires":[["bc62ca0fab4a2ec3"]]},{"id":"bc62ca0fab4a2ec3","type":"switch","z":"a669fa3740561e95","name":"Status code check","property":"statusCode","propertyType":"msg","rules":[{"t":"lte","v":"acceptCode","vt":"msg"},{"t":"gte","v":"retryCode","vt":"msg"}],"checkall":"true","repair":false,"outputs":2,"x":630,"y":160,"wires":[[],["785188d617170876"]]},{"id":"94fe5b4f69e781c1","type":"comment","z":"a669fa3740561e95","name":"RETRY FAIL","info":"","x":890,"y":260,"wires":[]},{"id":"e27355a7416b6817","type":"subflow:a669fa3740561e95","z":"8ce345fe79ab93d5","name":"","env":[{"name":"maxAttempts","value":"20","type":"str"},{"name":"pollPeriod","value":"20000","type":"str"},{"name":"method","value":"GET","type":"str"}],"x":600,"y":200,"wires":[["3541f048c54690ad"],["818b6d18a19261e8"],["f2f30be4fa42062a"]]},{"id":"cb3dc78c15526cb1","type":"inject","z":"8ce345fe79ab93d5","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":100,"y":80,"wires":[["3060cf272dab827f"]]},{"id":"46410c7fb06e9b7c","type":"function","z":"8ce345fe79ab93d5","name":"add OW activation id from reply","func":"\nmsg.activationID=msg.headers['x-openwhisk-activation-id'];\n\nmsg.url='http://10.100.59.182:3233/api/v1/namespaces/_/activations/'+msg.activationID;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":290,"y":200,"wires":[["e27355a7416b6817"]]},{"id":"3541f048c54690ad","type":"debug","z":"8ce345fe79ab93d5","name":"SUCCESS","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":850,"y":180,"wires":[]},{"id":"818b6d18a19261e8","type":"debug","z":"8ce345fe79ab93d5","name":"RETRY FAIL","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":850,"y":220,"wires":[]},{"id":"f2f30be4fa42062a","type":"debug","z":"8ce345fe79ab93d5","name":"FINAL FAIL","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":850,"y":260,"wires":[]},{"id":"eeae0f4f8ab394d9","type":"http request","z":"8ce345fe79ab93d5","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":470,"y":80,"wires":[["ae081f620c0a5458"]]},{"id":"3060cf272dab827f","type":"function","z":"8ce345fe79ab93d5","name":"insert action url","func":"msg.url='http://10.100.59.182:3233/api/v1/web/guest/default/dockeraction.json?delay=80000'\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":80,"wires":[["eeae0f4f8ab394d9"]]},{"id":"ae081f620c0a5458","type":"switch","z":"8ce345fe79ab93d5","name":"Code check","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"eq","v":"202","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":670,"y":80,"wires":[["650448bc8f3549cc"],["46410c7fb06e9b7c"]]},{"id":"650448bc8f3549cc","type":"debug","z":"8ce345fe79ab93d5","name":"FINISHED SUCCESSFULLY","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":900,"y":60,"wires":[]}]

Flow Info

Created 2 years, 3 months ago
Rating: 3 2

Owner

Actions

Rate:

Node Types

Core
  • comment (x3)
  • debug (x4)
  • delay (x1)
  • function (x4)
  • http request (x2)
  • inject (x1)
  • switch (x3)
Other
  • subflow (x1)
  • subflow:a669fa3740561e95 (x1)

Tags

  • polling
  • pushing
  • openwhisk
  • invocation
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option