3

I want to make a function that calls an API (third party) and returns immediately, but it is waiting for API response.

Here is the code sample:

var request = require('request');

// When I call functionOne it should trigger functionTwo and should end immediately, 
// but unfortunately, it is waiting for functionTwo to end
module.exports.functionOne = (event, context, cb) => {
    const uri = 'https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/functionTwo';
    request.post({ uri: uri });
    cb(null, "done functionOne");
};

module.exports.functionTwo = (event, context, cb) => {
    console.log("i'm functionTwo");
    setTimeout(function () {
        console.log("I'm functionTwo about to end");
        context.succeed("done functionTwo");
    }, 5000);
};

Moreover, if i try to call context.succeed() instead of cb(), it even prevent API call and function return immediately without calling the API.

I have also created an issue on GitHub.

Additional info:

  • Serverless Framework: v1.0.0-rc.2
  • Node: v6.9.1
  • OS: Win 10
Zanon
  • 29,231
  • 20
  • 113
  • 126
Inzamam Malik
  • 3,238
  • 3
  • 29
  • 61

2 Answers2

3

Sorry, but you can't achieve what you want, at least not in this way.

When you call another function using request.post(), you must provide a callback and you must wait for it to finish.

What you could do is to call request.abort(), but this is a hacky solution.

module.exports.functionOne = (event, context, cb) => {
    const uri = 'https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/functionTwo';
    const r = request.post({ uri: uri }, (error, response, body) => {
        cb(error, "done functionOne");
    });

    r.abort();
    cb(null, 'forced abort on functionOne');
};

Why is this hacky? Because you can't abort immediately. You need to wait a few milliseconds for the request to be received in the other server, but there is no way to know exactly when it happens.

If you know that the second Lambda will run for 2 minutes, you could add a setTimeout function to abort the request after 5 seconds and avoid having the functionOne running for a long time in a idle state. But again, this is a bad solution.

Why don't you place the functionTwo code inside functionOne to avoid starting a second Lambda?

Another workaround would be to call a SNS topic from functionOne and configure this topic to trigger functionTwo.

Zanon
  • 29,231
  • 20
  • 113
  • 126
  • FunctionTwo is here just for example, in actual case there is an api which is third party, and i'm sending post request to that api with some data, and actually it is slack api – Inzamam Malik Nov 22 '16 at 05:31
  • Ok, so I suggest that you create another question specific to the Slack API. If it was another Lambda function, you could use SNS because it returns in just a few milliseconds. If Slack takes several seconds to complete, I don't know if they provide another way to queue the request without needing to wait. – Zanon Nov 22 '16 at 08:53
  • Otherwise, you can abort the request to force Lambda to stop early, but as I said, you need to wait a few moments before Slack receives the request. – Zanon Nov 22 '16 at 08:56
  • aborting request does not solved my problem unfortunately – Inzamam Malik Nov 28 '16 at 17:05
0

In your handler you can use flag callbackWaitsForEmptyEventLoop = false

    module.exports.functionOne = (event, context, cb) => {
    context.callbackWaitsForEmptyEventLoop = false
    const uri = 'https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/functionTwo';
    request.post({ uri: uri });
    cb(null, "done functionOne");
    };