.NET Lambda调用SQS DeleteMessageAsync无响应 无法删除队列消息
.NET Lambda调用SQS DeleteMessageAsync挂起无响应问题排查
问题现象
基于.NET框架开发的SQS标准队列触发Lambda函数,预期消息处理完成后主动删除队列消息避免重复消费,核心实现代码如下:
using Amazon.Lambda.Core; using Amazon.Lambda.SQSEvents; using Amazon.Runtime; using Amazon.SQS; using Amazon.SQS.Model; [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] namespace AWSLambda1; public class Function { public Function() { } public async Task FunctionHandler(SQSEvent evnt, ILambdaContext context) { foreach (var message in evnt.Records) { if (ProcessMessage(message)) await DeleteMessage(message, context); } } private static bool ProcessMessage(SQSEvent.SQSMessage message) { Console.WriteLine($"\nMessage body of {message.MessageId}:"); Console.WriteLine($"{message.Body}"); return true; } private static async Task DeleteMessage(SQSEvent.SQSMessage message, ILambdaContext context) { var sqsClient = new AmazonSQSClient(); var qUrl = "https://sqs.eu-north-1.amazonaws.com/XXXXXXXXXX/TestQueue"; try { context.Logger.LogInformation($"\nDeleting message {message.MessageId} from queue..."); context.Logger.LogInformation($"\nReceipt Handle: {message.ReceiptHandle}"); var deleteReq = new DeleteMessageRequest { QueueUrl = qUrl, ReceiptHandle = message.ReceiptHandle }; var deleteResp = await sqsClient.DeleteMessageAsync(deleteReq); // This block of code is never reached context.Logger.LogInformation($"\nDeleted message {message.MessageId} from queue..."); context.Logger.LogInformation($"\nDeleted message with status {deleteResp.HttpStatusCode}"); } catch (Exception e) { context.Logger.LogInformation($"\nEXCEPTION ON DELETE MESSAGE {e.Message} from queue..."); throw; } } }
代码参考官方示例编写,排查过程中未在日志中发现任何错误输出,日志样例如下:
2022-06-28T22:30:19.441+03:00 START RequestId: c86729c3-5df9-57b0-8b46-72f6050fae56 Version: $LATEST 2022-06-28T22:30:19.805+03:00 2022-06-28T19:30:19.748Z c86729c3-5df9-57b0-8b46-72f6050fae56 info 2022-06-28T22:30:19.805+03:00 Message body of 9a99b479-66f5-4740-afb5-6dc9693e5907: 2022-06-28T22:30:19.805+03:00 2022-06-28T19:30:19.805Z c86729c3-5df9-57b0-8b46-72f6050fae56 info test 2022-06-28T22:30:20.425+03:00 2022-06-28T19:30:20.425Z c86729c3-5df9-57b0-8b46-72f6050fae56 info 2022-06-28T22:30:20.425+03:00 Deleting message 9a99b479-66f5-4740-afb5-6dc9693e5907 from queue... 2022-06-28T22:30:20.425+03:00 2022-06-28T19:30:20.425Z c86729c3-5df9-57b0-8b46-72f6050fae56 info 2022-06-28T22:30:20.425+03:00 Receipt Handle: AQEBH/vZmNFFir4oshRJxMGtOAAuu+KcboUqRnFWNCseksSAT+ShxslAaRJP1BoDk6L+3iSvMoxdRUcspHCfY40hZumCZvJnuD8U0IEOG6jwRMdORjP7oTpdsRoV/ZloAQL5tJzlK/jRHRWlsTPr1n1IpkS4sXgPnD8fxrW0OiG3ARX/N/ii1RsWLMZnc4tgYFpGicuKdT0/EzdUonenTwDut4KHQVZWbu4nisqc6y2IyyhZwOXyfzLoc7Jk+DeCulRZPpcPRUk1qeUoLExc3fSnFukMtizm8i2to82OaKqkc27ZFyXRGQzEChL5ed/Z1RRPTUlSt/qzgjye2IXhvU2u6piZ/kFpV4v7+3tQ2Ts1oMCs5M+HiONS1wVlqlpGzAunSDmpaXtZF+7HAk97LeYPPg== 2022-06-28T22:30:49.451+03:00 END RequestId: c86729c3-5df9-57b0-8b46-72f6050fae56
从日志可以看到,DeleteMessageAsync调用后的两行日志始终不会执行,请求等待约30秒后直接结束,无异常抛出、无删除成功响应返回,消息无法正常删除。
排查方向与根因定位
从日志时间差判断:打印完Receipt Handle的时间点是22:30:20,请求结束时间是22:30:49,间隔恰好29秒,和Lambda默认30秒超时阈值吻合,说明请求全程卡在网络等待阶段,没有收到任何服务端响应(包括错误响应),因此既不会执行后续成功逻辑,也不会进入catch块,最终被Lambda运行时强制终止。按优先级从高到低排查以下问题即可解决:
- 网络连通性问题(90%概率为该原因)
首先检查Lambda的VPC配置:如果Lambda部署在自定义VPC的私有子网内,默认没有公网访问能力,无法连通SQS的公网服务端点,会导致TCP请求直接挂起。两种修复方案二选一:给私有子网绑定NAT网关提供公网出口,或者在对应VPC内创建SQS服务的VPC端点,通过内网访问SQS。
同时检查Lambda绑定的安全组出站规则,确认没有拦截到SQS服务443端口的出站流量。 - SQS客户端配置问题
不要在每次执行DeleteMessage时重复实例化AmazonSQSClient,将客户端初始化逻辑移到Function构造函数中做单例复用,避免每次调用重复建立TCP连接引发连接异常。
初始化客户端时显式指定和队列一致的eu-north-1区域,不要依赖SDK的默认区域自动探测,Lambda环境下自动探测逻辑偶尔会因元数据服务访问超时导致请求挂起。同时给客户端配置显式的请求超时,避免请求无限挂住无法抛出异常,修正后的初始化代码如下:
后续删除消息时直接复用构造函数中初始化的private readonly AmazonSQSClient _sqsClient; private const string QUrl = "https://sqs.eu-north-1.amazonaws.com/XXXXXXXXXX/TestQueue"; public Function() { var sqsConfig = new AmazonSQSConfig { RegionEndpoint = RegionEndpoint.EUNorth1, Timeout = TimeSpan.FromSeconds(5) }; _sqsClient = new AmazonSQSClient(sqsConfig); }_sqsClient即可。 - 权限配置校验
确认Lambda执行角色绑定的权限策略包含sqs:DeleteMessage操作,资源字段正确填写目标SQS队列的ARN,避免权限不足导致的请求失败。 - 超时配置校验
不要使用Lambda默认3秒超时配置,至少将Lambda超时时间设置为10秒以上,给SDK的重试逻辑预留足够时间。
注:SQS作为Lambda事件源时,只要函数执行未抛出异常,Lambda服务会自动批量删除处理成功的消息,无需手动调用DeleteMessage接口,可减少自定义代码的异常风险。
内容的提问来源于stack exchange,提问作者realnsleo
相关产品推荐
相关产品推荐

