You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

批量更新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);
}

问题分析

  1. 方法逻辑错误:ExecuteBulkUpdate方法内定义的ExecuteTransactionRequest是局部变量,外部的循环和异常处理块根本访问不到,等于没正确构建批量请求。
  2. 同步调用阻塞:_serviceClient.Execute是同步调用,加上批量处理的耗时,很容易触发Http触发Function的默认5分钟超时限制。
  3. 分批逻辑混乱:判断分批的条件用了multipleRequestWithResults.Requests.Count,但实际收集数据的是requestsCollection.Entities,变量不匹配导致分批逻辑失效。
  4. 遗漏剩余记录:循环结束后,最后一批不足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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 09:20:13