【问题标题】:How to call an aws java lambda function from another AWS Java Lambda function when both are in same account, same region当两个 AWS Java Lambda 函数都在同一个账户、同一个区域时,如何从另一个 AWS Java Lambda 函数调用一个 aws java lambda 函数
【发布时间】:2021-04-14 05:12:24
【问题描述】:

我有一个 java aws lambda 函数或处理程序作为 AHandler,它可以做一些事情,例如它已订阅 SNS 事件,它解析该 SNS 事件并将相关数据记录到数据库中。

我有另一个 java aws lambda BHandler,这个 BHandler 的目标是接收来自 AHandler 的请求并向 AHandler 提供响应。因为 BHandler 的目标是提供带有一些 json 数据的响应。这将被 AHandler 使用。

我可以看到任何清楚的例子来说明我们如何做这些事情吗?

我看到了这个例子call lambda function from a java classInvoke lambda function from java

我的问题是关于这种情况,当一个 aws java lambda 函数(或处理程序)调用另一个 aws java lambda 函数时,而两者都在同一个区域、同一个帐户、相同的 vpc 执行内容、相同的权限。 在这种情况下,aws java lambda 函数可以直接调用(或调用)另一个函数,还是必须提供 aws 键、区域等内容(如上面的链接)?一个清晰的例子/解释会很有帮助。

编辑

正在调用另一个 Lambda 函数 (BHandler) 的 AHandler,存在于同一帐户中,已提供完整的 AWSLambdaFullAccess 与所有内容,例如

“iam:PassRole”, "λ:*",

这里是调用代码:

注意:当我从普通的 java 主函数调用相同的函数时,下面的代码可以正常工作。但它不像从 lambda 函数调用(比如 ALambdaHandler 调用 BLambdaHandler 作为函数调用)。 即使它没有返回任何异常。它只是显示超时,它卡在以下代码中: lambdaClient.invoke

String awsAccessKeyId = PropertyManager.getSetting("awsAccessKeyId");
        String awsSecretAccessKey = PropertyManager.getSetting("awsSecretAccessKey");
        String regionName = PropertyManager.getSetting("regionName");
        String geoIPFunctionName = PropertyManager.getSetting("FunctionName");

        Region region;
        AWSCredentials credentials;
        AWSLambdaClient lambdaClient;

        credentials = new BasicAWSCredentials(awsAccessKeyId,
                awsSecretAccessKey);

        lambdaClient = (credentials == null) ? new AWSLambdaClient()
                : new AWSLambdaClient(credentials);
        region = Region.getRegion(Regions.fromName(regionName));
        lambdaClient.setRegion(region);


        String returnGeoIPDetails = null;

        try {


            InvokeRequest invokeRequest = new InvokeRequest();
            invokeRequest.setFunctionName(FunctionName);
            invokeRequest.setPayload(ipInput);


            returnDetails = byteBufferToString(
                    lambdaClient.invoke(invokeRequest).getPayload(),
                    Charset.forName("UTF-8"),logger);
        } catch (Exception e) {

            logger.log(e.getMessage());
        }

编辑 我按照别人的建议做了一切,并遵循了一切。最后我联系了 AWS 支持,问题与一些 VPC 配置有关,并且得到了解决。如果您遇到类似的问题,那么可能是检查安全配置,VPC 的东西。

【问题讨论】:

  • 任何人调用 Lambda 函数的唯一方法是通过 Lambda API。它们是否在同一个帐户、区域或什至在同一物理机器上都没有关系(无论如何您都无法知道)。您必须使用InvokeFunction API 调用。
  • 似乎很重要,当我从笔记本电脑(intellij)的独立 java 程序调用 aws lambda 函数时,它运行良好,但是当我从同一帐户的另一个 aws lambda 函数调用相同的 aws lambda 函数时, 相同的区域, 它给出了超时。两者会有不同的配置,但不确定此类文档或示例存在于何处。
  • 顺便说一句,您不应在 Lambda 环境中指定 aws 凭证。这是一个糟糕的设计。在这种情况下,您应该像 new AWSLambdaClient(new DefaultAWSCredentialsProviderChain()); 一样启动 LambdaClient,AWS sdk 以您在执行角色中拥有的权限运行。
  • 嗨 Sumit,AWS Support 推荐的 VPC 配置到底是什么?我面临着类似的问题,但即使在尝试了以下答案中建议的几乎所有内容后也无法获得解决方案。
  • @rupesh ,我几年前做过那个工作,所以现在我离开这个并参与其他工作,所以我没有任何细节

标签: java amazon-web-services aws-lambda


【解决方案1】:

我们通过使用 com.amazonaws.services.lambda.model.InvokeRequest 实现了这一点。 这是代码示例。

public class LambdaInvokerFromCode {
     public void runWithoutPayload(String functionName) {
            runWithPayload(functionName, null);
        }

        public void runWithPayload(String functionName, String payload) {
            AWSLambdaAsyncClient client = new AWSLambdaAsyncClient();
            client.withRegion(Regions.US_EAST_1);

            InvokeRequest request = new InvokeRequest();
            request.withFunctionName(functionName).withPayload(payload);
            InvokeResult invoke = client.invoke(request);
            System.out.println("Result invoking " + functionName + ": " + invoke);
    }



    public static void main(String[] args) {
            String KeyName ="41159569322017486.json";
            String status = "success";
            String body = "{\"bucketName\":\""+DBUtils.S3BUCKET_BULKORDER+"\",\"keyName\":\""+KeyName+"\", \"status\":\""+status+"\"}";
            System.out.println(body);

            JSONObject inputjson = new JSONObject(body); 
            String bucketName = inputjson.getString("bucketName");
            String keyName = inputjson.getString("keyName");
            String Status = inputjson.getString("status");
            String destinationKeyName = keyName+"_"+status;
            LambdaInvokerFromCode obj = new LambdaInvokerFromCode();
            obj.runWithPayload(DBUtils.FILE_RENAME_HANDLER_NAME,body);
        }
}

【讨论】:

    【解决方案2】:

    编辑:对于这种情况,请考虑使用Step Functions

    【讨论】:

    • 我按照建议做了,请参阅我添加了更多详细信息的问题,但我仍然没有找到任何解决方案。它卡在 lambdaClient.invoke 上,没有抛出任何异常。总体上没有给出任何线索来做什么。
    • Lambda 运行时期望处理程序返回一个对象,直到您的 lambda 达到超时。如果没有返回,它将停止该过程。上面的代码不返回任何东西。尝试从函数返回任何对象。您还可以记录来自 InvokeLambda 的结果,以便查看是否有任何结果从 InvokeLambda 返回。
    • 感谢@Çağatay Gürtürk,我按照您的建议做了一切并遵循了一切。最后我联系了 AWS 支持,问题与一些 VPC 配置有关,并且得到了解决。
    • 你是指第二名还是第三名?
    【解决方案3】:

    我们遇到了类似的问题,并试图收集各种实现来实现这一点。原来它与代码无关。

    一些基本规则:

    1. 确保您的 lambda 函数具有正确的策略和角色,至少: { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:::" }, { "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": [ "" ] } ] }
    2. 在同一地区有功能。

    3. 不需要 VPC 配置。如果您的应用程序具有 VPC,请确保您的 lambda 函数具有适当的角色策略(请参阅 AWSLambdaVPCAccessExecutionRole)

    4. 最重要的(主要是我们失败的原因),设置正确的超时和堆大小。调用 Lambda 将等到被调用者完成。 2x 被调用的 lambda 值的简单数学计算有效。此外,这仅适用于调用另一个 java lambda 函数的 java lambda 函数。使用 node js lambda 函数调用另一个 lambda 函数没有这个问题。

    以下是一些适合我们的实现:

    1. 使用服务接口
    
    
        import com.amazonaws.regions.Regions;
        import com.amazonaws.services.lambda.AWSLambdaAsyncClientBuilder;
        import com.amazonaws.services.lambda.invoke.LambdaInvokerFactory;
        import com.amazonaws.services.lambda.runtime.Context;
        import com.amazonaws.services.lambda.runtime.RequestHandler;
    
        public class LambdaFunctionHandler implements RequestHandler {
    
            @Override
            public String handleRequest(Object input, Context context) {
                context.getLogger().log("Input: " + input);
    
                FineGrainedService fg = LambdaInvokerFactory.builder()
                        .lambdaClient(
                                AWSLambdaAsyncClientBuilder.standard()
                                .withRegion(Regions.US_EAST_2)
                                .build()
                        )
                        .build(FineGrainedService.class);
    
                context.getLogger().log("Response back from FG" + fg.getClass());
    
                String fgRespone = fg.callFineGrained("Call from Gateway");
                context.getLogger().log("fgRespone: " + fgRespone);
    
                // TODO: implement your handler
                return "Hello from Gateway Lambda!";
            }
    
        }
    
    
        import com.amazonaws.services.lambda.invoke.LambdaFunction;
    
        public interface FineGrainedService {
    
            @LambdaFunction(functionName="SimpleFineGrained")
            String callFineGrained(String input);
        }
    
    
    
    1. 使用调用程序
    
    
        import java.nio.ByteBuffer;
    
        import com.amazonaws.services.lambda.AWSLambdaClient;
        import com.amazonaws.services.lambda.model.InvokeRequest;
        import com.amazonaws.services.lambda.runtime.Context;
        import com.amazonaws.services.lambda.runtime.RequestHandler;
    
        public class LambdaFunctionHandler implements RequestHandler {
    
            @Override
            public String handleRequest(Object input, Context context) {
                context.getLogger().log("Input: " + input);
    
                AWSLambdaClient lambdaClient = new AWSLambdaClient();
                try {
                    InvokeRequest invokeRequest = new InvokeRequest();
                    invokeRequest.setFunctionName("SimpleFineGrained");
                    invokeRequest.setPayload("From gateway");
    
                    context.getLogger().log("Before Invoke");
                    ByteBuffer payload = lambdaClient.invoke(invokeRequest).getPayload();
                    context.getLogger().log("After Inoke");
    
                    context.getLogger().log(payload.toString());
                    context.getLogger().log("After Payload logger");
    
                } catch (Exception e) {
                    // TODO: handle exception
                }
    
                // TODO: implement your handler
                return "Hello from Lambda!";
            }
    
        }
    
    

    AWSLambdaClient 应该从构建器创建。

    【讨论】:

      【解决方案4】:

      您可以使用LambdaClient 通过传递InvocationType.EVENT 参数来异步调用Lambda。看一个例子:

      LambdaClient lambdaClient = LambdaClient.builder().build();
      InvokeRequest invokeRequest = InvokeRequest.builder()
              .functionName("functionName")
              .invocationType(InvocationType.EVENT)
              .payload(SdkBytes.fromUtf8String("payload"))
              .build();
      InvokeResponse response = lambdaClient.invoke(invokeRequest);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-23
        • 1970-01-01
        • 2018-01-13
        相关资源
        最近更新 更多