openfaas / templates

OpenFaaS Classic templates
https://www.openfaas.com
MIT License
276 stars 228 forks source link

Node.js template to support promise/async/await #172

Closed padiazg closed 4 years ago

padiazg commented 4 years ago

Signed-off-by: Patricio Diaz padiazg@gmail.com

This template introduces the possibility of using Promise or Async/Await on the handler function, in addition of the callback approach used before.

Description

In index.js the value returned by handler.js is checked to figure out if it is the final result or is a Promise so it can be retrieved and handled properly.

Motivation and Context

We need to handle the latest asynchronicity mechanism provided by the language, which are Promises and Async/Await

Fixes issue #92

Which issue(s) this PR fixes

Fixes #92

How Has This Been Tested?

For a Callback version of handler.js

$ faas new node-cb --lang node --prefix padiazg

handler.js

"use strict"

// A simple delay function
const delayCallback = cb => {
    const min = 0; // 0 sec
    const max = 2; // 2 sec
    const delay = Math.round((Math.random() * (max - min) + min));
    setTimeout(() => cb(delay),  delay * 1000);
}

// callback version
module.exports = (context, callback) => {
    delayCallback(delay => callback(undefined, {status: context || "callback", delay}))
}
$ faas up -f node-cb.yml
$ echo -n "cb" | faas invoke node-cb -
{"status":"cb","delay":1}

For a Promise version of handler.js

$ faas new node-promise --lang node --prefix padiazg

handler.js

"use strict"

// A simple delay function
const delayCallback = cb => {
    const min = 0; // 0 sec
    const max = 2; // 2 sec
    const delay = Math.round((Math.random() * (max - min) + min));
    setTimeout(() => cb(delay),  delay * 1000);
}

// Uncomment the following line to use it with the promise or async/await versions
const delayPromise = () => new Promise(resolve => delayCallback(delay => resolve(delay)) )

module.exports = context => new Promise((resolve, reject) => {
    delayPromise()
    .then(delay => {
        resolve({status: context || "promise", delay});
    })
})
$ faas up -f node-promise.yml
$ echo -n "prom" | faas invoke node-promise -
{"status":"prom","delay":2}

For a Async/Await version of handler.js

$ faas new node-async-await --lang node --prefix padiazg

handler.js

"use strict"

// A simple delay function
const delayCallback = cb => {
    const min = 0; // 0 sec
    const max = 2; // 2 sec
    const delay = Math.round((Math.random() * (max - min) + min));
    setTimeout(() => cb(delay),  delay * 1000);
}

// Uncomment the following line to use it with the promise or async/await versions
const delayPromise = () => new Promise(resolve => delayCallback(delay => resolve(delay)) )

module.exports = async context => {
    const delay = await delayPromise();
    return {status: context || "async/await", delay}
}
$ faas up -f node-promise.yml
$ echo -n "async" | faas invoke node-async-await -
{"status":"async","delay":0}

Types of changes

Impact to existing users

Hopefully wont break existing functions

Checklist:

padiazg commented 4 years ago

Yes, it will work as usual. Then a suitable example will be just on the documentation?

padiazg commented 4 years ago

I'll leave it as the original, just adding the promises/async/await support for this template.

padiazg commented 4 years ago

Tell me, we will still support callback as a way to call handler.js?

alexellis commented 4 years ago

I've tested these two combinations:

"use strict"

module.exports = (context, callback) => {
  callback(null, "done, via CB");
}
"use strict"

module.exports = async (context, callback) => {
  return "done";
}

Both worked as expected 👍