У меня очень странное поведение службы Async. История есть: Там плагин, который стреляет по Lead Create
. Целью самого плагина является создание пользовательского перечисления Leads. Плагин получает последний номер из поля в объекте Autonumbering, который хранит числа. Затем плагин увеличивает поле номера Autonumbering entity на 1 и присваивает полученное число Lead.Async Service обрабатывает объект несколько раз
Проблема заключается в следующем: Когда я запускаю массовое создание проводов (испытание на краш для нумерации), например. 400, а счетчик автоматического запуска начинается с 0, когда все проводники обработаны, мой счетчик Autonumbering заканчивается значением ~ 770, что намного больше, чем оценено 400.
Я по опыту обнаружил, что службы Async обрабатывают то же самое несколько раз. Для одних только 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());
}
}
UPDATE 1: Сначала мои переменные контекстно-заводской службы были объявлены в классе, чтобы они могли быть использованы по одному экземпляру для нескольких потоков.
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);;
[...]
}
}
Но это не спасло меня от многократной обработки, хотя обработка теперь идет очень быстро.
UPDATE 2: В системе Джобсом я также заметил, что после 11 операций со статусом Retry Count = 0
операции остальные имеют Retry Count = 1
, а после 16 лет она Retry Count = 2
и т.д.
(в этом тесте я создал 20 потенциальных клиентов programmaticaly, и после того, как распайке счетчик показывает мне last number = 33
, и если я могу суммировать все retry count
значения она выходит с 33, который похож на last number
в автонумерация)
Где 'context' и' 'обслуживания взялся? Похоже, ваш код не является потокобезопасным. –
@HenkvanBoeijen, я ответил в UPDATE 1 в вопросе. –
Повторения, возможно, это рабочий процесс, пытающийся получить блокировку и пропуская ее, вы должны попробовать повторить попытку с помощью Thread.Sleep, поэтому рабочий процесс ждет, чтобы получить блокировку. – dynamicallyCRM