【问题标题】:Microsoft Dynamics CRM Plugins - Concurrent updatesMicrosoft Dynamics CRM 插件 - 并发更新
【发布时间】:2019-11-22 15:53:00
【问题描述】:

我有一个自定义实体,它具有近乎实时的更新(每分钟大约 1000 次更新)。由于同一实体记录可能在不同的批量更新请求中得到更新,并且请求是从不同的异步源接收的,因此 CDS 中较新的更新可能会被稍旧的更新覆盖。

  1. 实体记录 A 的 Update-1(自定义属性 datamodifiedon 设置为 8.02 PM)由异步服务 S1 处理。
  2. 实体记录 A 的 Update-2(自定义属性 datamodifiedon 设置为 8.03 PM)由异步服务 S2 处理。

由于网络延迟或其他原因,S1 服务稍微慢了一点,服务 S2 继续并在晚上 8 点 3 分对实体记录 A 进行了更新调用。

Service-1 现在在同一实体记录上触发 Update-1,并且发生在 8.03PM 的更新被发生在 8.02PM 的更新覆盖,从而导致数据丢失。

我在第 10 阶段(预验证)为我的自定义实体的更新 SDK 消息注册了一个插件。 此插件将来自输入参数的 datamodifiedon 属性与来自插件上下文的 pre-entity 图像中的一组进行比较。 如果前实体图像已经具有更新的 datamodifiedon 属性,则抛出 Invalid Plugin Execution 异常。

// If ModifiedOn value in pre-image is later than the one received in input parameters, this is an obsolete request and must be rejected.
if (preImage.Contains("datamodifiedon")
    && preImage.GetAttributeValue<DateTime>("datamodifiedon") != DateTime.MinValue
    && entity.Contains("datamodifiedon")
    && entity.GetAttributeValue<DateTime>("datamodifiedon") != DateTime.MinValue
    )
{
    if (DateTime.Compare(preImage.GetAttributeValue<DateTime>("datamodifiedon"), entity.GetAttributeValue<DateTime>("datamodifiedon")) > 0)
    {
        string traceMessage = "PreOperationLiveWorkItemUpdatePlugin: Update request is obsolete. datamodifiedon field found in pre-entity image: "
            + preImage.GetAttributeValue<DateTime>("datamodifiedon")
            + "datamodifiedon field in Input parameters: "
            + entity.GetAttributeValue<DateTime>("datamodifiedon");

        tracingService.Trace(traceMessage);
        throw new InvalidPluginExecutionException(traceMessage);
    }
}

由于更新非常频繁,是否有可能 1. Update-2 (datamodifiedon 8.03 PM) 处于预验证阶段。验证成功后,数据库中的实际更新正在进行中。 2. 现在Update-1 进入预验证阶段。由于 Update-2 还没有提交到数据库中,在这个阶段接收到的 pre-entity 图像是否仍然是旧值并让验证通过?

由于其他两个阶段在同一个数据库事务中执行,因此在 Pre-Operation 或 Post-Operation 阶段注册此插件是否会有所帮助而不是 Pre-Validation 阶段?

还有其他方法可以解决这个并发问题吗?由于更新是通过批量 odata 调用启动的,因此无法在请求标头中使用 eTag 前置条件。

【问题讨论】:

    标签: plugins dynamics-crm microsoft-dynamics dynamics-crm-online concurrentmodification


    【解决方案1】:

    您想在预操作步骤中注册此插件。我认为您对可能脏的前实体图像有一个有效的担忧(我不确定是否在事务中检索了前图像),因此不要使用前图像检索记录的新副本并检查检索到的记录的时间戳与目标上的时间戳对比。由于您的所有操作都是针对同一张表的同步事务,并且时间戳是该表上的一个字段,我认为这将保证您没有脏写。

    但是:
    如果您的 Update1 和 Update2 操作更新不同的字段,现在您可能会遭受反向数据丢失。如果 Update1 设置字段 A 并且 update2 设置字段 B,则所做的更改 如果在更新到字段 B 之后处理,则字段 A 将被忽略。

    【讨论】:

    • 感谢您的回复。 dataupdatedon 字段将在每个更新请求的目标实体中可用。所以,我们在这方面很好。我唯一关心的是:如果插件为两个更新并行执行,则前置实体图像不会对其他更新的事务数据进行脏读。前实体图像将类似于数据库中已提交的记录。如果 Update2 在操作前步骤中 Update1 的验证成功后立即提交到 CDS DB,Update1 是否仍会继续并覆盖?
    • 我认为您对前实体图像可能很脏有一个合理的担忧,我相应地更新了我的答案。
    • 感谢更新的答案。鉴于我们正在发生实时数据更新,我担心如果这个额外的检索调用会对每分钟更新的记录数造成更多的延迟和性能影响。有了可用的选择,您建议在哪个阶段注册插件?验证前 (10) 或操作前 (20) 或操作后 (30) 这些阶段中的任何一个阶段是否会比其他阶段提供额外的优势?
    • 您需要在操作前执行此操作,以便它成为更新事务的一部分。这确实需要在每次写入操作期间进行少量额外读取,但是 Arun 建议的 Optimistic Concurrency(看起来很酷)大概也需要在后台进行额外的读取操作。
    【解决方案2】:

    您应该尝试使用Optimistic concurrency。如果您可以在更新之前检查行版本。

    乐观并发功能使您的应用程序能够检测在您的应用程序检索记录和尝试更新或删除该记录之间的时间里,服务器上的实体记录是否发生了变化。

    Code example

    【讨论】:

    • 感谢您的回复。我是否需要在预验证/预操作插件中显式检索记录?这会进一步延迟更新还是对一分钟内可以更新的记录数量产生影响?
    • 您应该从正在更新它的源中检索它,因此它知道如果它失败了该怎么办。那么你甚至不需要插件来处理并发。
    猜你喜欢
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    • 1970-01-01
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-09
    相关资源
    最近更新 更多