33

I need to invoke aws lambda from another lambda asynchronously. i have a working code for synchronous calls.

exports.handler = (event, context, callback) => {
    var aws = require('aws-sdk');
    var lambda = new aws.Lambda({
        region: 'myregion' //change to your region
    });
    console.log("lambda invoke started");
    lambda.invoke({
        FunctionName: 'testLambda',
        Payload: JSON.stringify(event, null, 2) // pass params
    }, function (error, data) {
        if (error) {
            console.log("error");
            callback(null, 'hello world');
        }
        else {
            console.log("lambda invoke end");
            callback(null, 'hello world');
        }
    });
}

But in my case, 'testLambda' is a time taken function. Because i need to exit just after invoking the 'testLambda' function. Then code is updated like this

exports.handler = (event, context, callback) => {
    var aws = require('aws-sdk');
    var lambda = new aws.Lambda({
        region: 'myregion' //change to your region
    });
    console.log("lambda invoke started");
    lambda.invoke({
        FunctionName: 'testLambda',
        Payload: JSON.stringify(event, null, 2) // pass params
    });
    console.log("lambda invoke end");
    callback(null, 'hello world');
}

it returns message correctly . But my 'testLambda' function is not invoked(no cloud watch logs are generated for test lambda). what is the issue related with this code.

Abdul Manaf
  • 4,933
  • 8
  • 51
  • 95

5 Answers5

39

Per the Lambda invoke() documentation, you will see that by default the Lambda function is invoked using the RequestResponse invocation type. To invoke the function asynchronously you need to specify the Event invocation type, like so:

lambda.invoke({
    FunctionName: 'testLambda',
    InvocationType: 'Event',
    Payload: JSON.stringify(event, null, 2)
},function(err,data){});
mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Mark B
  • 183,023
  • 24
  • 297
  • 295
29

I was working with the currently latest node.js 8.10 version in AWS Lambda.
The second lambda didn't execute (and the callback function was never called) until i used the async/await mechanism.
So the handler function must be async, and the 'lambda.invoke' call be wrapped with a Promise.

here is my working code:

function invokeLambda2(payload) {
    const params = {
        FunctionName: 'TestLambda2',
        InvocationType: 'Event',
        Payload: JSON.stringify(payload)
    };

    return new Promise((resolve, reject) => {

        lambda.invoke(params, (err,data) => {
            if (err) {
                console.log(err, err.stack);
                reject(err);
            }
            else {
                console.log(data);
                resolve(data);
            }
        });     
    });
}


exports.handler = async (event, context) => {
    const payload = {
        'message': 'hello from lambda1'
    };
    await invokeLambda2(payload);
    context.done();
};

Please notice that the handler doesn't wait for the second lambda to exit, only for it to be triggered and the callback function being called.

You could also return the Promise from within the handler, don't have to use await with a second function.

No need for any import when working with Promises and async/await, other than:

const AWS = require('aws-sdk');
const lambda = new AWS.Lambda();
ronginat
  • 1,910
  • 1
  • 12
  • 23
  • 2
    When you get an AccessDeniedException don't forget to add the "AWSLambdaRole" policy to your IAM role. { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": [ "*" ] } ] } – Joenas May 15 '19 at 12:20
  • 2
    Works like a charm, just a side note that a good response for async invocation is: `INFO { StatusCode: 202, Payload: '' }` (from CloudWatch Logs) – Meir Gabay Dec 15 '19 at 10:58
  • Worked 2 days to make the lambda.invoke work properly, my god finally found this solution which is working like a charm. Thanks for posting this solution. – Coder0997 Dec 25 '19 at 02:40
  • 1
    I think this code is not async. If you are doing await invokeLambda2(payload); then you are making the sencond lambda execution in a sync way. Do I missing something? @ronginat – Juan Ignacio Barisich Feb 08 '21 at 17:00
  • 1
    Well, it's 'async' just like every other piece of code you wrap with a `Promise`. Pay attention that the invocation of the second lambda is separate from its actual execution. So it'll execute without any wait needed for the source lambda. This answer is relevant in case your main handler is async and you wish to wait for another lambda to be invoked in an async way. – ronginat Feb 08 '21 at 21:21
  • It's working for me after adding await as mentioned but my second lambda is always executing exactly twice at the same time.What could be probably the issue ? @ronginat – shashank chandak Jan 25 '22 at 07:47
6

With reference to Ronginat's answer, instead of wrapping lambda.invoke() in a Promise, you could directly use lambda.invoke().promise() and do something like this: (tested in Node.js 12.x)

exports.handler = async (event) => {

    const payload = 'hello from lambda 1';

    const params = {
        FunctionName: 'lambda2',
        InvocationType: 'Event',
        Payload: JSON.stringify(payload),
    };

    const LambdaPromise = (params) => lambda.invoke(params).promise();

    const responseFromLambda2 = await LambdaPromise(params);

    return responseFromLambda2; //this should return {StatusCode: 202, Payload: ''}
};
Ardent Coder
  • 3,777
  • 9
  • 27
  • 53
kirtap
  • 121
  • 1
  • 5
4

I wanted a similar solution as above. Though step functions are now recommended when using multiple lambda functions over lambda.invoke , I used the following code snippet to asynchronously call two other lambda functions from my base lambda function.

var AWS = require('aws-sdk');
AWS.config.region = 'ap-southeast-1';
var lambda = new AWS.Lambda();

exports.handler = async(event) => {
   await invokeLambda(event);
   
   const response = {
        statusCode: 200,
        body: JSON.stringify('success'),
   };
   
   return response;
};

//Invoke Multiple Lambda functions
  async function invokeLambda(event) {
    const function1 = {
        FunctionName: 'dev-test-async-lambda-1',
        InvocationType: 'Event',
        Payload: JSON.stringify(event)
    };

    const function2 = {
        FunctionName: 'dev-test-async-lambda-2',
        InvocationType: 'Event',
        Payload: JSON.stringify(event)
    };
    
    await lambda.invoke(function1).promise();
    await lambda.invoke(function2).promise();

}

        

Let me know if I can improve this.

Cnf271
  • 302
  • 5
  • 16
2

That's how I use in Express.js


var express = require("express");
var router = express.Router();

const asyncMiddleware = fn =>
  (req, res, next) => {
    Promise.resolve(fn(req, res, next))
      .catch(next);
  };

const invokeLambda = async (params) => {
  const data = await lambda.invoke(params).promise();
  return JSON.parse(data.Payload);
}


router.get('/test', asyncMiddleware(async (req, res, next) => {
  const params = {
    FunctionName: SOMETHING_LAMBDA_ARN,
    Payload: JSON.stringify(req.body)
  };
  const result = await invokeLambda(params);
  res.send(result);
}));

Miae Kim
  • 1,713
  • 19
  • 21