【发布时间】:2016-09-26 15:08:45
【问题描述】:
我的异步服务有一个非常奇怪的行为。
故事是:
有一个插件,在Lead Create 上触发。插件本身的目的是创建潜在客户的自定义枚举。该插件从保存数字的自动编号实体中的字段中获取最后一个数字。然后插件将自动编号实体的编号字段加 1,并将获得的编号分配给潜在客户。
问题如下: 当我运行大量创建潜在客户(编号碰撞测试)时,例如400,自动编号计数器从 0 开始,当所有潜在客户处理完毕后,我的自动编号计数器以 ~770 的值结束,比估计的 400 多得多。
根据经验,我发现异步服务多次处理相同的线索。有些人只有1次,有些人是2-5次。
为什么会这样?
这是我的代码:
public void Execute(IServiceProvider serviceProvider)
{
Entity target = ((Entity)context.InputParameters["Target"]);
target["new_id"] = GetCurrentNumber(service, LEAD_AUTONUMBER);
service.Update(target);
return;
}
public int GetCurrentNumber(IOrganizationService service, Guid EntityType)
{
lock (_locker)
{
Entity record = service.Retrieve("new_autonumbering", EntityType, new ColumnSet("new_nextnumber"));
record["new_nextnumber"] = int.Parse(record["new_nextnumber"].ToString()) + 1;
service.Update(record);
return int.Parse(record["new_nextnumber"].ToString());
}
}
更新 1: 首先,我的 context-factory-service 变量在类中声明,因此它们可以在一个实例中用于多个线程。
public class IdAssignerPlugin : IPlugin
{
private static IPluginExecutionContext context;
private static IOrganizationServiceFactory factory;
private static IOrganizationService service;
public void Execute(IServiceProvider serviceProvider)
{
context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
service = factory.CreateOrganizationService(null);
[...]
}
}
在 @HenkvanBoeijen 的评论之后,我意识到这不是安全的方式,所以我将所有声明移到了 Execute() 方法中。
public class IdAssignerPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));;
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));;
IOrganizationService service = factory.CreateOrganizationService(null);;
[...]
}
}
但这并没有让我免于多次处理,尽管现在处理速度非常快。
更新 2: 在 System Jobs 中,我还注意到在 11 次操作后状态为 Retry Count = 0 其余操作为 Retry Count = 1,16 次后为 Retry Count = 2 等。
(在这个测试中,我以编程方式创建了 20 个潜在客户,分配后计数器显示last number = 33,如果我总结所有retry count 值,它会得到33,这类似于自动编号中的last number)
【问题讨论】:
-
context和service来自哪里?看起来您的代码不是线程安全的。 -
@HenkvanBoeijen ,我在问题的更新 1 中回答了。
-
重试可能是工作流试图获取锁并跳过,您应该尝试使用 Thread.Sleep 重试,以便工作流等待获取锁。
-
@dynamicallyCRM ,当工作流遇到lock()时,默认休眠。
标签: c# asynchronous plugins dynamics-crm-2011 crm