【问题标题】:Is it a good idea to call one AWS Lambda from another with an APIGatewayProxyRequest?使用 APIGatewayProxyRequest 从另一个 AWS Lambda 调用一个好主意吗?
【发布时间】:2021-06-10 17:08:09
【问题描述】:

这个问题的灵感来自另一个:Is it a good idea to invoke lambda from other lambda in AWS lambda service?

我正在使用 netcoreapp3.1 和 C# 开发 lambda。

我有一个接受来自 API Gateway 的 HTTP 请求的 lambda A。我按照https://aws.amazon.com/blogs/developer/running-serverless-asp-net-core-web-apis-with-amazon-lambda 使用dotnet 模板serverless.AspNetCoreWebAPI,其中我的lambda 函数对调用作出反应,就好像它是一个Web api。

我还有另一个 lambda B,它也被 API Gateway 调用,只是这次它获取 websocket 事件(CONNECT、DISCONNECT、MESSAGE)。

我正在考虑让 lambda B 同步调用 lambda A。

流程如下:API Gateway > Lambda B > Lambda A

我有一个两难选择:

  • 直接从 Lambda B 调用 Lambda A 是一个好主意吗?
  • 还是让 Lambda B 向 API Gateway 发送一个 http 请求,然后让网关调用 Lambda A 来完成它的工作?
  • 或者我是否应该忘记将 Lambda A 功能公开为“http”并在 Lambda A 中拥有一个接受任何有效负载的单一入口点,以便 Lambda B 可以使用自定义消息调用它?

在成本和性能方面,我想没有太大区别,但从 Lambda B 调用 Lambda A 似乎“更容易”,因为我真正需要的只是知道函数的名称。

这是我的尝试,我使用了

public async Task<APIGatewayProxyResponse> FunctionHandler(
    APIGatewayProxyRequest apiGatewayProxyRequest, 
    ILambdaContext context)
{
    context.Logger.LogLine("Get Request\n");
    var isWebSocketRequest = apiGatewayProxyRequest.HttpMethod is null;
    if (!isWebSocketRequest)
    {
        throw new ArgumentException(
            $"Received Http method {apiGatewayProxyRequest.HttpMethod}, not a valid websocket event");
    }

    var result = await ProcessWebsocketEvent(apiGatewayProxyRequest, context.Logger);
    return result;
}

private async Task<APIGatewayProxyResponse> ProcessWebsocketEvent(APIGatewayProxyRequest apiGatewayProxyRequest, ILambdaLogger logger)
{
    var eventType = apiGatewayProxyRequest.RequestContext.EventType;
    string body = eventType;
    if ("CONNECT" == eventType)
    {
        body += $", connection={apiGatewayProxyRequest.RequestContext.ConnectionId}";
    }
    else if ("DISCONNECT" == eventType)
    {
        body += $", connection={apiGatewayProxyRequest.RequestContext.ConnectionId}";
    }
    else if ("MESSAGE" == eventType)
    {
        body += $", body={apiGatewayProxyRequest.Body}";
    }

    logger.LogLine("Creating amazon lambda client..");
    using var lambdaClient = new AmazonLambdaClient(RegionEndpoint.EUWest3);
    var payload =
        new
        {
            Foo = "bar",
            Bar = "foo"
        };
    var json = JsonSerializer.Serialize(payload);
    logger.LogLine($"With payload {payload}");
    var request =
        new InvokeRequest
        {
            FunctionName = "lambda-dotnet-webapi-function",
            Payload = json
        };
    
    var responseInvoke = await lambdaClient.InvokeAsync(request);
    using var stream = new StreamReader(responseInvoke.Payload);
    var responsePayload = await stream.ReadToEndAsync();

    var response = new APIGatewayProxyResponse
    {
        StatusCode = (int) HttpStatusCode.OK,
        Body = responsePayload,
        Headers = new Dictionary<string, string> {{"Content-Type", "text/plain"}}
    };
    return response;
}

我注意到的第一件事。如果我有 3 秒超时,它会超时。我必须增加它。 如果我将它增加到 10 秒,我可以得到一个调用,因为调用请求的有效负载不是“正确的”

{"statusCode":200,"headers":{"Content-Type":"text/plain"},"body":"{\n  \"errorType\": \"NullReferenceException\",\n  \"errorMessage\": \"Object reference not set to an instance of an object.\",\n  \"stackTrace\": [\n    \"at Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction.MarshallRequest(InvokeFeatures features, APIGatewayProxyRequest apiGatewayRequest, ILambdaContext lambdaContext)\",\n    \"at Amazon.Lambda.AspNetCoreServer.AbstractAspNetCoreFunction`2.FunctionHandlerAsync(TREQUEST request, ILambdaContext lambdaContext)\",\n    \"at lambda_method(Closure , Stream , Stream , LambdaContextInternal )\"\n  ]\n}\n","isBase64Encoded":false}

Lambda A 运行 800 毫秒 Lambda B 运行 9000 毫秒(9 秒,很多......)

这让我想到了另一个问题。 如果这是一种可接受的方法,我怎样才能像 Lambda B 是“代理”一样发送请求?

我正在考虑以 http-ish 方式调用 Lambda A,主要是因为我真的很喜欢库 https://github.com/aws/aws-lambda-dotnet/tree/master/Libraries/src/Amazon.Lambda.AspNetCoreServer,它允许我的 Lambda 被实现为标准的 aspNet web api,阅读 appsettings,依赖注入,使用测试服务器等进行测试。

查看 Lambda A 日志我可以看到以下警告

[Warning] Amazon.Lambda.AspNetCoreServer.AbstractAspNetCoreFunction: Request does not contain domain name information but is derived from APIGatewayProxyFunction. 

以及我在 Lambda B 中作为响应得到的异常:

Object reference not set to an instance of an object.: NullReferenceException
   at Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction.MarshallRequest(InvokeFeatures features, APIGatewayProxyRequest apiGatewayRequest, ILambdaContext lambdaContext)
   at Amazon.Lambda.AspNetCoreServer.AbstractAspNetCoreFunction`2.FunctionHandlerAsync(TREQUEST request, ILambdaContext lambdaContext)
   at lambda_method(Closure , Stream , Stream , LambdaContextInternal )

【问题讨论】:

  • 如果您不需要 Lambda A 的响应,那么这可能会起作用吗? Lambda B => SQS => Lambda A.
  • 我需要回复。它必须是同步的,这就是为什么我想要一个请求/响应有效负载并将其视为代理请求或类似请求。除非我把 lambda A 和 lambda B 放在一起,让它在同一个函数中处理更多的事情,否则那里会有一些不可避免的耦合,这似乎也不理想。

标签: c# .net-core aws-lambda aws-api-gateway


【解决方案1】:

问题是您正在从 lambda B 连接,而 lambda A 需要预热这个 coulf 需要几秒钟(至少 3 秒),所以如果您在 lambda B 上的超时为 3 秒,您会收到超时

对此的解决方案是保持对您的 lambda A 进行预热,可能使用 ping 操作,但这意味着您大部分时间都会有一个 lambda

其他东西

你能补充一下

InvocationType = InvocationType.RequestResponse,

调用请求

【讨论】:

  • 我现在不太担心响应时间,因为你提到这是由于 lambda 没有被加热。我关心的是触发 lambda A 的最佳方式是什么,以及是直接触发还是通过 api 网关触发。感谢您的调用类型,我将探索它
  • 也许更好地调用网关,考虑到将来您可以通过 ECS 或 EC2 资源中的应用程序更改您的 lambda,在同源协议 (REST) 上使用您的 API,所以现在是更容易调用 lambda,但是如果您必须更改应用程序的位置,则必须更改更多内容,我认为您可能需要考虑您的应用程序是否会及时更改,或者您不会在很长时间内触及它我认为是一种权衡
猜你喜欢
  • 2017-08-15
  • 2018-08-21
  • 2016-12-31
  • 2020-03-28
  • 2020-02-08
  • 1970-01-01
  • 2018-06-09
  • 2021-11-04
  • 1970-01-01
相关资源
最近更新 更多