【发布时间】: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