.NET 6独立架构V4函数Cosmos操作频繁出现取消异常求助
问题背景
- 基于.NET 6独立架构的V4 Azure Functions
- CosmosClient初始化代码:
var cosmosClient = CosmosClient.CreateAndInitializeAsync(cosmosSettings?.Endpoint, cosmosSettings?.Key, containers).Result; services.AddSingleton(cosmosClient); - 仓储类通过构造函数获取容器,仅实现
Save方法调用UpsertItemAsync执行数据写入 - 批量执行逻辑:每次迭代创建25个异步任务调用
Save,通过ContinueWith捕获异常,最终await Task.WhenAll等待全部完成
异常现象
- App Insights上报大量Create/Query操作被取消的异常,但数据可正常入库
- 自定义日志未捕获到对应异常信息
- 当前请求量约250万次/小时,大量零RU成本的失败依赖记录严重干扰问题排查
解决方案
1. 修复CosmosClient初始化的同步阻塞问题
使用.Result会强制阻塞线程,可能引发上下文混乱或死锁,改为异步注入方式:
services.AddSingleton<CosmosClient>(async sp => { var cosmosSettings = sp.GetRequiredService<CosmosSettings>(); return await CosmosClient.CreateAndInitializeAsync(cosmosSettings.Endpoint, cosmosSettings.Key, containers); });
确保
CosmosSettings已正确注入,避免空引用异常。
2. 替换ContinueWith为可靠的异步异常捕获
ContinueWith在异步场景下容易丢失异常上下文,且无法正确捕获取消类异常,建议在Save方法内部直接处理异常:
public async Task Save(ItemDbo itemDbo) { try { await _container.UpsertItemAsync(itemDbo); } catch (OperationCanceledException ex) { _logger.LogWarning(ex, $"Upsert operation canceled for item {itemDbo.Id}"); } catch (CosmosException ex) { _logger.LogError(ex, $"Upsert failed for item {itemDbo.Id}, Status Code: {ex.StatusCode}"); } catch (Exception ex) { _logger.LogCritical(ex, $"Unexpected error during upsert for item {itemDbo.Id}"); } }
批量任务创建可简化为:
var taskList = new List<Task>(); foreach (var itemDbo in targetItems) { taskList.Add(Save(itemDbo)); } await Task.WhenAll(taskList);
3. 调整CosmosClient的超时与重试策略
默认配置可能无法应对高并发场景,延长超时时间并优化限流重试:
var cosmosClientOptions = new CosmosClientOptions { RequestTimeout = TimeSpan.FromSeconds(30), MaxRetryAttemptsOnRateLimitedRequests = 10, MaxRetryWaitTimeOnRateLimitedRequests = TimeSpan.FromSeconds(30) }; services.AddSingleton<CosmosClient>(async sp => { var cosmosSettings = sp.GetRequiredService<CosmosSettings>(); return await CosmosClient.CreateAndInitializeAsync( cosmosSettings.Endpoint, cosmosSettings.Key, containers, cosmosClientOptions); });
4. 排查函数执行超时问题
Azure Functions默认存在执行超时限制(消费计划为5分钟),如果批量任务执行时间过长,会被函数宿主强制终止,导致Cosmos请求被取消:
- 检查函数配置(
function.json或[FunctionName]属性)中的超时参数,按需调整 - 高并发下拆分批量任务大小,例如从单次25个减少到10个,避免单次函数执行负载过高
5. 验证Cosmos容器RU配置
虽然异常显示零RU成本,但高并发下RU不足会触发限流,客户端重试过程中可能因函数超时被取消。需确认容器RU配置足够支撑250万次/小时的请求量,或开启RU自动缩放功能。
内容的提问来源于stack exchange,提问作者macm
相关产品推荐
相关产品推荐

