批量更新Dynamics CRM时Azure Function超时问题求解
问题描述
我有一个Http触发的Azure Function,用于更新Dynamics CRM中的数据。待更新数据量超过10万条,因此我使用ExecuteTransaction请求进行分批处理,但Azure Function在执行完第一个批次后就超时,无法继续处理后续记录。
说明:未使用webhook,因是批量更新,我直接调用Azure Function的URL触发它。
用户提供的代码:
foreach (var item in list) { var cust = new Entity("account"); cust.Id = list.Id; cust["code] = 1; cust["description"] = "Test"; requestsCollection.Entities.Add(cust); if (multipleRequestWithResults.Requests.Count == 1000) { ExecuteBulkUpdate(multipleRequestWithResults); requestsCollection = new EntityCollection(); } } public void ExecuteBulkUpdate(EntityCollection requestsCollection) { var requests = new ExecuteTransactionRequest { Requests = new OrganizationRequestCollection(), ReturnResponses = true }; } foreach (var request in requestsCollection.Entities) { UpdateRequest updateRequest = new UpdateRequest { Target = request }; requests.Requests.Add(updateRequest); } try { _serviceClient.Execute(requests); } catch (FaultException<OrganizationServiceFault> ex) { _logger.LogInformation("Request failed for the {0} and the reason being: {1}", ((ExecuteTransactionFault)(ex.Detail)).FaultedRequestIndex + 1, ex.Detail.Message); throw; } public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function,"get","post", Route = "")] HttpRequestData req) { // Call the bulk update from here return req.CreateResponse(HttpStatusCode.OK); }
问题分析
- 方法逻辑错误:
ExecuteBulkUpdate方法内定义的ExecuteTransactionRequest是局部变量,外部的循环和异常处理块根本访问不到,等于没正确构建批量请求。 - 同步调用阻塞:
_serviceClient.Execute是同步调用,加上批量处理的耗时,很容易触发Http触发Function的默认5分钟超时限制。 - 分批逻辑混乱:判断分批的条件用了
multipleRequestWithResults.Requests.Count,但实际收集数据的是requestsCollection.Entities,变量不匹配导致分批逻辑失效。 - 遗漏剩余记录:循环结束后,最后一批不足1000条的记录没有被处理。
解决方案
1. 修正代码核心逻辑
先把代码里的变量作用域、分批判断、异步调用等问题修复:
// 分批处理主逻辑 public async Task ProcessBulkUpdatesAsync() { var requestsCollection = new EntityCollection(); foreach (var item in list) { var cust = new Entity("account"); cust.Id = item.Id; // 原代码错误:误用list.Id,改为item.Id cust["code"] = 1; // 修复引号不闭合问题 cust["description"] = "Test"; requestsCollection.Entities.Add(cust); // 每收集1000条就执行一次批量更新 if (requestsCollection.Entities.Count == 1000) { await ExecuteBulkUpdateAsync(requestsCollection); requestsCollection = new EntityCollection(); } } // 处理最后一批不足1000条的记录 if (requestsCollection.Entities.Count > 0) { await ExecuteBulkUpdateAsync(requestsCollection); } } // 异步批量更新方法 public async Task ExecuteBulkUpdateAsync(EntityCollection requestsCollection) { var transactionRequest = new ExecuteTransactionRequest { Requests = new OrganizationRequestCollection(), ReturnResponses = true // 如果不需要响应,设为false可提升性能 }; foreach (var entity in requestsCollection.Entities) { var updateRequest = new UpdateRequest { Target = entity }; transactionRequest.Requests.Add(updateRequest); } try { // 改用异步执行方法,避免阻塞 await _serviceClient.ExecuteAsync(transactionRequest); } catch (FaultException<OrganizationServiceFault> ex) { _logger.LogInformation("第 {0} 个请求失败,原因:{1}", ((ExecuteTransactionFault)ex.Detail).FaultedRequestIndex + 1, ex.Detail.Message); throw; } } // 修正Http触发方法,确保异步执行 public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function,"get","post", Route = "")] HttpRequestData req) { await ProcessBulkUpdatesAsync(); return req.CreateResponse(HttpStatusCode.OK); }
2. 延长Function超时时间
Http触发的Azure Function默认超时是5分钟,在host.json中修改为最大允许的10分钟:
{ "version": "2.0", "functionTimeout": "00:10:00" }
3. 用队列拆分大任务(推荐)
如果10分钟仍不够处理10万条数据,建议把任务拆分成多个小批次,用Azure Queue Storage触发处理:
- 步骤1:Http触发Function只负责拆分数据,把每个批次的记录ID列表存入Azure Queue。
- 步骤2:创建Queue触发的Function,每次从队列取出一个批次,执行Dynamics CRM更新。
- 这样每个批次独立处理,Queue触发的Function超时也可设为10分钟,且Azure会自动扩容多个实例并行处理,大幅提升效率。
4. 优化Dynamics CRM调用
- 缩小批次大小:如果1000条单次请求耗时太长,可调整为500条,减少单次请求的处理压力。
- 关闭响应返回:如果不需要每个更新请求的结果,把
ReturnResponses设为false,减少数据传输开销。
内容的提问来源于stack exchange,提问作者MVC_Nhibernate
相关产品推荐
相关产品推荐

