从另一个Lambda异步调用AWS Lambda

33

我需要从另一个 Lambda 异步地调用 AWS Lambda。我已经有一个可以进行同步调用的工作代码。

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');
        }
    });
}

但在我的情况下,'testLambda'是一个耗时函数。因为我需要在调用'testLambda'函数后立即退出。那么代码被更新如下:

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');
}
它可以正确地返回消息,但是我的“testLambda”函数没有被调用(测试 Lambda 没有生成 CloudWatch 日志)。这个代码有什么问题?
5个回答

40
根据 Lambda invoke() 文件,您会发现默认情况下使用 RequestResponse 调用类型来调用 Lambda 函数。要异步调用函数,您需要指定 Event 调用类型,像这样:
lambda.invoke({
    FunctionName: 'testLambda',
    InvocationType: 'Event',
    Payload: JSON.stringify(event, null, 2)
},function(err,data){});

29

我正在使用目前AWS Lambda中最新的node.js 8.10版本进行工作。
在我使用async/await机制之前,第二个lambda没有被执行(回调函数也从未被调用)。
因此,处理程序函数必须是异步的,并且'lambda.invoke'调用必须用Promise进行包装。

这是我的工作代码:

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();
};
请注意,处理程序不会等待第二个lambda退出,只是等待其被触发并调用回调函数。
您还可以从处理程序中返回 Promise ,无需使用第二个函数 await
在处理Promise和async / await时,除以下情况外,无需进行任何导入:
const AWS = require('aws-sdk');
const lambda = new AWS.Lambda();

2
当您遇到AccessDeniedException时,请不要忘记将“AWSLambdaRole”策略添加到IAM角色中。 { “Version”:“2012-10-17”, “Statement”:[ { “Effect”:“Allow”, “Action”:[ “lambda:InvokeFunction” ], “Resource”:[ “*” ] } ] } - Joenas
2
运行得非常好,只是需要注意的是异步调用的良好响应是:INFO { StatusCode: 202, Payload: '' }(来自 CloudWatch 日志) - Meir Gabay
为了让lambda.invoke正常工作,我花了两天时间,我的天啊,终于找到了这个完美的解决方案。感谢您发布这个解决方案。 - Coder0997
1
我认为这段代码不是异步的。如果您正在执行 await invokeLambda2(payload); 那么您正在以同步方式执行第二个 lambda。我是否漏了什么?@ronginat - Juan Ignacio Barisich
1
好的,就像你用Promise包装的其他代码一样,它也是“async”的。请注意,第二个lambda表达式的调用与其实际执行是分开的。因此,它将在不需要等待源lambda的情况下执行。如果您的主处理程序是异步的,并且希望以异步方式等待另一个lambda被调用,则此答案很相关。 - ronginat
在我添加了所提到的await之后,它对我起作用了,但我的第二个lambda总是同时执行两次。可能的问题是什么? @ronginat - shashank chandak

6

关于Ronginat的回答, 你可以直接使用lambda.invoke().promise()而不是将lambda.invoke()包装在一个Promise中,然后可以像下面这样做:(已在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: ''}
};

4

我希望能够找到与上述类似的解决方案。虽然在使用多个lambda函数时,现在推荐使用步骤函数而不是lambda.invoke,但我仍然使用以下代码片段从我的基本lambda函数异步调用另外两个lambda函数。

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();

}

        

如果我可以改进这个,请让我知道。


2
这是我在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);
}));


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接