AWS Lambda函数可以调用另一个函数吗?

454

我有2个Lambda函数 - 一个生成报价,另一个将报价转换为订单。 我希望Order Lambda函数调用Quote函数重新生成报价,而不是仅从不受信任的客户端接收报价。

我已经寻找了我能想到的所有地方 - 但是不知道如何链接或调用这些函数...肯定有这样的函数存在!


2
我有些猜测,但为什么第一个 Lambda 函数不能依赖 AWS JavaScript SDK,创建一个 AWS.Lambda 客户端并 invoke 第二个函数呢? - devonlazarus
1
显然,您还可以通过HTTP调用Lambda函数。 - devonlazarus
4
还有一个想法,你可以通过社交网络服务(SNS)来将它们链接起来,这可能是我会采用的更可扩展的策略。 - devonlazarus
9
还有另外两种常见的替代方案未在此提到,它们分别是 Step Functions 和 SWF。 - lebryant
1
@ManthanJamdagni 调用 Lambda 函数与该函数的 VPC 配置完全独立。VPC 子网、路由、安全组等都与调用无关(特别是对于调用而言)。 - jarmod
显示剩余4条评论
22个回答

491
我找到了一种使用aws-sdk的方法。
var aws = require('aws-sdk');
var lambda = new aws.Lambda({
  region: 'us-west-2' //change to your region
});

lambda.invoke({
  FunctionName: 'name_of_your_lambda_function',
  Payload: JSON.stringify(event, null, 2) // pass params
}, function(error, data) {
  if (error) {
    context.done('error', error);
  }
  if (data.Payload) {
    context.succeed(data.Payload);
  }
});

您可以在此处找到文档:http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html


44
使用社交网络可能是更好的方法,但这是正确答案。 - Silver
54
我可能错了,但我认为由于调用是同步的,因此第一个 Lambda 等待第二个 Lambda 终止,这样在两个 Lambda 运行时您将会产生费用。使用 SNS,第一个 Lambda 应该终止并允许第二个 Lambda 独立执行。 - dev
111
由于 InvocationType: 'Event' 参数的帮助,我成功地使它工作了(将其添加到 FunctionNamePayload 之后)。根据文档:_"您可以通过指定 InvocationType 为 Event 来选择异步执行。"_ 使用异步执行,回调函数将被可靠地调用,而无需等待被调用的 Lambda 执行完成。 - Alessandro
39
请注意,调用 Lambda 函数的角色需要包括 IAM 策略 AWSLambdaRole。或者,您可以将以下语句对象添加到您的角色现有策略中:'{ "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": ["*"] }' - Bob Arlof
请查看 Lambda 目标。 - emilio
此外,在使用此方法调用函数时要小心。您可能会陷入无限调用循环中,而在这种情况下停止调用的唯一方法是上传代码的新版本。 - ArjunPunnam

161
你应该通过SNS链接你的Lambda函数。这种方法在付出最小努力的同时,提供了良好的性能、延迟和可扩展性。
你的第一个Lambda函数发布消息到你的SNS主题,而第二个Lambda函数订阅了这个主题。一旦消息到达主题,第二个Lambda函数就会被执行,并将消息作为其输入参数。
请参阅使用Amazon SNS通知调用Lambda函数
你还可以使用这种方法来通过SNS调用跨账户的Lambda函数

12
"您应该通过 SNS 链接 Lambda 函数" -- 您能提供支持此建议的证据/文档链接吗?我知道这两种方法都可以工作,但我希望看到一些关于哪种方法更受推荐的意见/明确声明。 - Claude
50
如果你需要异步操作,这是一个好主意。 但是如果你的第一个 lambda 函数需要第二个 lambda 返回的值,你必须链接这两个 lambda 并且让第一个 lambda 直接调用第二个 lambda。 - Noel Llevares
13
我不建议使用SNS。除非你想通知多个订阅者而不仅仅是触发另一个Lambda函数,否则你可以只使用异步调用API来调用Lambda函数。 - user3807087
11
请记住,社交网络服务不能保证信息的送达,因此您可能发送了消息但它未能到达。 - Bart Van Remortele
3
为了解决交付保证的问题,您可以通知一个SQS队列,并使用重试模式来确保成功处理数据。 https://aws.amazon.com/sqs/faqs/ - nigfasa
显示剩余9条评论

107
这是一段Python的示例代码:
from boto3 import client as boto3_client
from datetime import datetime
import json

lambda_client = boto3_client('lambda')

def lambda_handler(event, context):
    msg = {"key": "new_invocation", "at": datetime.now().isoformat()}
    invoke_response = lambda_client.invoke(FunctionName="another_lambda_",
                                           InvocationType='Event',
                                           Payload=json.dumps(msg))
    print(invoke_response)

顺便提一下,您还需要将此策略添加到您的 Lambda 角色中

   {
        "Sid": "Stmt1234567890",
        "Effect": "Allow",
        "Action": [
            "lambda:InvokeFunction"
        ],
        "Resource": "*"
    }

5
我也更喜欢这种方法,但它有一个小缺陷。你需要将datetime.now()转换为字符串(或以某种方式处理)。否则,你会收到错误消息:datetime.datetime(2017, 9, 11, 14, 40, 53, 23834) is not JSON serializable - John C
第一个 lambda 的角色是否可以更加严格限制?例如,将其限制为仅调用特定函数,而不是任何函数? - Phil
@Phil 或许“资源”字段可以设置为仅允许特定的一组函数,但我并不完全确定。 - Chenna V
4
InvocationType 应为 RequestResponse,以获取您尝试调用的 Lambda 函数的响应。 - ambigus9
1
然后,如果您的 InvocationTypeRequestResponse,您应该打印 print(invoke_response['Payload'].read().decode()) 以正确打印响应消息。 - Prageeth Jayathissa
显示剩余2条评论

53
自从这个问题被提出以来,亚马逊发布了Step Functions (https://aws.amazon.com/step-functions/)。
AWS Lambda 的核心原则之一是您可以更专注于业务逻辑,而不必过多关注将所有内容紧密联系在一起的应用程序逻辑。Step Functions 允许您编排函数之间的复杂交互,而无需编写执行此操作的代码。

19

这个解决方案是使用boto3和Python完成的:

import boto3
import json

lambda_client = boto3.client('lambda', region_name='eu-west-1')

def lambda_handler(event, context):
    lambda_client.invoke(FunctionName = 'function_name', InvocationType = 'RequestResponse', Payload = json.dumps(event))
    
    return True

7
InvocationType从以下选项中选择。RequestResponse(默认)- 同步调用函数。保持连接打开,直到函数返回响应或超时。Event - 异步调用函数。将多次失败的事件发送到函数的死信队列(如果已配置)。DryRun - 验证参数值并验证用户或角色是否具有调用函数的权限。 - Trilok Nagvenkar

13

我本来想放弃使用SNS,直到我在Lambda客户端文档(Java版本)中看到了这个:

用于访问AWS Lambda的客户端。使用此客户端进行的所有服务调用都是阻塞的,并且在服务调用完成之前不会返回。

因此,SNS具有明显的优势:它是异步的。您的lambda将不会等待后续的lambda完成。


25
InvocationType='Event'会使它异步化。请参阅http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Lambda.html#invoke-property。 - Ankit
3
@Ankit应该是被选中的答案,我被误导认为只有使用SNS才能进行异步调用,因为没有人提供这方面的信息。 - user3807087
@Ankit,你知道使用Java而不是JavaScript的InvocationType ='Event'的示例吗?有大量的Java文档,但是JavaScript的示例并不多。 - Talador12
SNS的使用仍会增加成本。 - Sebastien H.
1
@SebastienH。调用Lambda的SNS没有任何费用。https://aws.amazon.com/sns/pricing/ - fdaugan

11

Amazon于2016年在AWS Lambda中引入了步骤函数。我认为,现在使用步骤函数更加方便,因为它们真的很容易使用。您可以使用两个Lambda函数构建状态机,分别是:

  • 生成报价
  • 将报价转换成订单

您可以轻松地按照以下方式完成此操作:

这里您可以拥有生成报价的第一个状态和将其转化为订单的另一个状态

{
  Comment: "Produce a quote and turns into an order",
  StartAt: "ProduceQuote",
  States: {
    ProduceQuote: {
      "Type": Task,
      "Resource": "arn:aws:lambda:us-east-1:123456789012:function:ProduceQuote",
      "next": TurnsToOrder
    }
    TurnsToOrder: {
      Type: Task,
      Resource: "arn:aws:lambda:us-east-1:123456789012:function:ProduceQuote",
      end: true
    }
  }
}

使用Step Functions可以轻松编写多个Lambda函数,并按顺序或并行运行。

您可以在此处获取有关Lambda步骤函数的更多信息:Steps Functions


9

有很多答案,但是没有一个强调调用另一个lambda函数不是同步调用的推荐解决方案,你应该使用的真正解决方案是Step Functions

为什么不推荐使用这种解决方案:

  • 当它们彼此等待时,你需要支付两个函数的费用
  • 你的代码需要负责重试

你还可以将其用于相当复杂的逻辑,例如并行步骤和捕获失败。每次执行也都被记录下来,使得调试更加简单。


6
在Java中,我们可以按照以下方式进行操作:
AWSLambdaAsync awsLambdaAsync = AWSLambdaAsyncClientBuilder.standard().withRegion("us-east-1").build();

InvokeRequest invokeRequest = new InvokeRequest();
invokeRequest.withFunctionName("youLambdaFunctionNameToCall").withPayload(payload);

InvokeResult invokeResult = awsLambdaAsync.invoke(invokeRequest); 

在这里,payload是您需要传递给另一个lambda的字符串化Java对象,如果您需要从调用lambda传递一些信息到被调用的lambda,则需要将其作为Json对象传递。


我该如何传递目标 Lambda 所需的路径参数? - Ruelos Joel

5

我正在使用blueskin提供的答案进行工作,但由于InvocationType='Event'异步的,所以我无法读取有效载荷响应,因此我将其更改为InvocationType='RequestResponse',现在一切正常。


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