Node.js-从另一个Lambda函数中调用AWS.Lambda函数


73

我有以下函数,可用于从我的代码中调用Lambda函数。

但是,当我尝试在Lambda函数中使用它时,出现以下错误:

AWS lambda undefined 0.27s 3 retries] invoke({ FunctionName: 'my-function-name',
  InvocationType: 'RequestResponse',
  LogType: 'Tail',
  Payload: <Buffer > })

如何从Lambda函数中调用Lambda函数?

我的功能:

'use strict';

var AWS = require("aws-sdk");

var lambda = new AWS.Lambda({
    apiVersion: '2015-03-31',
    endpoint: 'https://lambda.' + process.env.DYNAMODB_REGION + '.amazonaws.com',
    logger: console
});

var lambdaHandler = {};

// @var payload - type:string
// @var functionName - type:string
lambdaHandler.invokeFunction = function (payload, functionName, callback) {

    var params = {
        FunctionName: functionName, /* required */
        InvocationType: "RequestResponse",
        LogType: "Tail",
        Payload: new Buffer(payload, 'utf8')
    };

    var lambdaRequestObj = lambda.invoke(params);

    lambdaRequestObj.on('success', function(response) {
        console.log(response.data);
    });

    lambdaRequestObj.on('error', function(response) {
        console.log(response.error.message);
    });

    lambdaRequestObj.on('complete', function(response) {
        console.log('Complete');
    });

    lambdaRequestObj.send();

    callback();
};

module.exports = lambdaHandler;

有没有理由将您的代码写lambda.invokeevent emitter而不是将其传递给回调函数?
nelsonic

是。这是用于Web服务器的,要求我在将响应发送给客户端之前不要等待Lambda的响应。
hyprstack

1
喔好吧。您可以直接触发,lambda.invoke忽略响应。
nelsonic

Answers:


135

使用aws-sdk每个Lambda中都提供的,从另一个Lambda函数中调用Lambda函数非常简单。

我建议先从简单的事情开始。
这是lambda内调用的“ Hello World”:

Lambda_ALambda_B 使用Payload包含一个参数的调用name:'Alex'
Lambda_B回应有效负载:"Hello Alex"

lambda调用

首先创建Lambda_B,它希望 在参数上有一个name 属性, 并使用以下命令响应请求:event
"Hello "+event.name

Lambda_B

exports.handler = function(event, context) {
  console.log('Lambda B Received event:', JSON.stringify(event, null, 2));
  context.succeed('Hello ' + event.name);
};

确保你给Lambda_BLambda_A相同的作用。
例如:创建一个lambdaexecute具有AWSLambdaExecute 的角色AWSLambdaBasicExecutionRole由于某些原因都需要):

Lambda角色用于Lambda内执行

Lambda_A

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

exports.handler = function(event, context) {
  var params = {
    FunctionName: 'Lambda_B', // the lambda function we are going to invoke
    InvocationType: 'RequestResponse',
    LogType: 'Tail',
    Payload: '{ "name" : "Alex" }'
  };

  lambda.invoke(params, function(err, data) {
    if (err) {
      context.fail(err);
    } else {
      context.succeed('Lambda_B said '+ data.Payload);
    }
  })
};

保存完这两个Lambda函数后,请运行以下命令Lambda_A

lambda invoke-lambda_a-execution-result

一旦完成了基本的lambdda内调用工作,就可以轻松扩展它以调用更复杂的Lambda函数。

您要记住的主要事情是为所有功能设置适当ARN Role的功能


我已经检查了region,vpc和所有内容,但是仍然无法调用lambda函数。我无法使用该功能。我们缺少任何新更新。您能帮忙吗,@ nelsonic
Arpit Vaishnav

1
@ArpitVaishnav可以使您的两个功能与AWSLambdaExecutePolicy发挥相同的作用。
nelsonic

是。请参考问题链接
Arpit Vaishnav,2016年

1
我要做的就是将所有可能的lambda策略添加到角色中。尝试搜索文本“ lambda”并添加所有这些自动建议的策略;)到目前为止,它确实起作用了...稍后将进行更深入的研究,以找出我可以取消的策略...
Mangesh Borkar

3
这对我不起作用,但是为角色添加InvokeFunction权限可以解决问题
fadiak

31

正如2016年12月3日,你可以简单地使用AWS阶跃函数把lambda函数Lambda_B作为的后续步骤,Lambda_A

借助AWS Step Functions,您可以将应用程序定义为状态机,这一系列步骤共同捕获了应用程序的行为。状态机中的状态可以是任务,顺序步骤,并行步骤,分支路径(选择)和/或计时器(等待)。任务是工作的单位,这项工作可以由AWS Lambda函数,任何类型的Amazon EC2实例,容器或在内部服务器上执行-可以与Step Functions API进行通信的任何事物都可以分配任务。

因此,以下状态机应满足您的需求。

在此处输入图片说明

这是与状态机相对应的代码。

{
  "Comment": "A simple example of the Amazon States Language using an AWS Lambda Function",
  "StartAt": "Lambda_A",

  "States": {
    "Lambda_A": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME",
      "Next": "Lambda_B"
    },
    "Lambda_B":{
      "Type": "Task",
      "Resource": "arn:aws:lambda:REGION:ACCOUNT_ID:function:FUNCTION_NAME",
      "End": true
    }

  }
}

此外,您可以在状态机中添加更为复杂的逻辑,例如并行步骤和捕获故障。它甚至记录每个执行的详细信息,这使调试有了更好的体验,尤其是对于lambda函数。

在此处输入图片说明


1
哇,谢谢你分享这个,我不知道这个存在,将来我会用的!看起来真的很有用!
Will Brickner

那么这是否意味着我们必须立即执行此步骤功能?还是将其自动配置到Lambda_A中(这样,当触发A时Lambda_B将自动执行)?
Michael Du

1
@MichaelDu您需要执行step函数而不是lambda。一个简单的方法来触发它使用API网关同样,你会触发你的lambda表达式,检查出这太问题的细节stackoverflow.com/questions/41188584/...
C.Lee

那么,这比从另一个lambda函数简单地执行lambda函数呢?Lambda B的执行可能取决于Lambda A中发生的情况,并需要从那里
获取

@Zigglzworth步进功能的主要优点是可以控制更复杂项目的整个工作流程。它使您可以有条件地免费执行lambda和wait函数,并且不受lambda函数的最大时间限制(300s)的限制。话虽如此,如果您只想链接两个lambda函数,那么可以,不使用step-function可能会更容易:)
C.Lee

8

@nelsonic提到的所有内容都是正确的,除了角色。

我尝试选择他上面提到的角色:

  • AWSLambdaExecute
  • AWSLambdaBasicExecutionRole

但是它不允许我调用其他lambda函数,因此我将角色更改为以下内容:

  • AWSLambda角色
  • AWSLambdaBasicExecutionRole

背后的原因是AWSLambdaExecute提供对S3的Put,Get访问以及对CloudWatch Logs的完全访问。但是 AWSLambdaRole为AWS Lambda服务角色提供了默认策略。 如果您遵守其许可政策,它将讨论invokeFunction

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

注意:可以在没有AWSLambdaBasicExecutionRole策略的情况下继续进行操作,因为它仅启用了在云中的日志监视功能。但是AWSLambdaRole是绝对必要的。


0

使用AWS.Lambda promises接口aws-sdk比使用回调更容易调用lambda 。

此示例函数使您可以从另一个lambda同步调用lambda(它'RequestResponse'用作InvocationType,因此您可以获取所调用的lambda返回的值)。

如果使用'Event'(用于异步调用),则无法获取被调用的lambda返回的值,只能检测是否可以成功调用lambda。它用于不需要从调用的lambda返回值的情况。

//
// Full example of a lambda that calls another lambda
//
// (create a lambda in AWS with this code)
//
'use strict';

//
// Put here the name of the function you want to call
//
const g_LambdaFunctionName = 'PUT_HERE_THE_INVOKED_LAMBDA_NAME'; // <======= PUT THE DESIRED VALUE

const AWS    = require('aws-sdk');
const lambda = new AWS.Lambda;

//
// Expected use:
//
//   // (payload can be an object or a JSON string, for example)
//   let var = await invokeLambda(lambdaFunctionName, payload);
//
const invokeLambda = async (lambdaFunctionName, payload) => {

   console.log('>>> Entering invokeLambda');

   // If the payload isn't a JSON string, we convert it to JSON
   let payloadStr;
   if (typeof payload === 'string')
   {
       console.log('invokeLambda:  payload parameter is already a string: ', payload);
       payloadStr = payload;
   }
   else
   {
       payloadStr = JSON.stringify(payload, null, 2);
       console.log('invokeLambda: converting payload parameter to a string: ', payloadStr);
   }

   let params = {
       FunctionName   : lambdaFunctionName,               /* string type, required */
       // ClientContext  : '',                               /* 'STRING_VALUE' */
       InvocationType : 'RequestResponse',                /* string type: 'Event' (async)| 'RequestResponse' (sync) | 'DryRun' (validate parameters y permissions) */
       // InvocationType : 'Event',

       LogType        : 'None',                           /* string type: 'None' | 'Tail' */
       // LogType        : 'Tail',
       Payload        : payloadStr,                       /* Buffer.from('...') || 'JSON_STRING' */ /* Strings will be Base-64 encoded on your behalf */
       //  Qualifier      : '',                             /* STRING_VALUE' */
   };

   //
   // TODO/FIXME: add try/catch to protect this code from failures (non-existent lambda, execution errors in lambda)
   //
   const lambdaResult = await lambda.invoke(params).promise();

   console.log('Results from invoking lambda ' + lambdaFunctionName + ': ' , JSON.stringify(lambdaResult, null, 2) );

   // If you use LogType = 'Tail', you'll obtain the logs in lambdaResult.LogResult.
   // If you use 'None', there will not exist that field in the response.
   if (lambdaResult.LogResult)
   {
       console.log('Logs of lambda execution: ',  Buffer.from(lambdaResult.LogResult, 'base64').toString());
   }

   console.log('invokeLambdaSync::lambdaResult: ', lambdaResult);

   console.log('<<< Returning from invokeLambda, with lambdaResult: ', JSON.stringify(lambdaResult, null, 2));

   // The actual value returned by the lambda it is lambdaResult.Payload
   // There are other fields (some of them are optional)
   return lambdaResult;
};

//
// We'll assign this as the calling lambda handler.
//
const callingFunc = async (event) => {

   //
   // in this example We obtain the lambda name from a global variable
   //
   const lambdaFunctionName = g_LambdaFunctionName;
   
   // const payload            = '{"param1" : "value1"}';
   const payload            = event;

   //
   // invokeLambda has to be called from a async function
   // (to be able to use await)
   //
   const result = await invokeLambda(lambdaFunctionName, payload);

   console.log('result: ', result);
};

// Assing handler function
exports.handler = callingFunc;

注意,您应该awaitinvokeLambda之前使用:

...
    //
    // Called from another async function
    //
    const result = await invokeLambda(lambdaFunctionName, payload);
...

一些带有附加信息的相关链接:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.