Контекст
Я написал инфраструктуру параллельных заданий на C# для импорта/экспорта большого объема данных из/в кластер ElasticSearch. Для этого я смоделировал каждый импорт или экспорт одного элемента как объект, который в какой-то момент выполняется фреймворком. Для взаимодействия с ElasticSearch я использую NEST (официальную клиентскую библиотеку .NET ElasticSearch) v1.7.1 и JSON.Net 7.0.1.
Каждый из объектов задачи импорта/экспорта взаимодействует с ElasticSearch с помощью NEST. Из соображений производительности я написал прокси-класс, который группирует поисковые запросы, сгенерированные объектами задач, в пакеты фиксированного размера для использования с _msearch API NEST. Вызывающий объект этого класса задерживается до тех пор, пока его пакет не вернется. Этот класс доступен здесь.
Моя структура обертывает модели результата каждой задачи импорта/экспорта либо как логическое значение, либо как исключение. Общий процесс может продолжаться, даже если встречаются ошибки с отдельными элементами.
Проблема
Я вижу следующее исключение, возникшее тысячи раз после нескольких часов выполнения задач без ошибок:
System.InvalidOperationException: Current error context error is different to requested error.
at _____.Matcher.<GetBestMatchAsync>d__15.MoveNext() in C:\\_work\\edc7a363\\_____\\Matcher.cs:line 266
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
_____.MatchBlock`1.<ExecuteAsyncInternal>d__19.MoveNext() in C:\\_work\\edc7a363\\_____\\MatchBlock.cs:line 111
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at _____.Block.BlockBase.<ExecuteAsync>d__11.MoveNext() in C:\\_work\\edc7a363\\_____\\Block\\BlockBase.cs:line 33
Это код, вызывающий исключение (из класса массового поиска, указанного выше):
try
{
var bulkResponse = Client.MultiSearch(searchDescriptor);
var items = bulkResponse.GetResponses<T>().ToList();
// Set response values and release all waiting tasks
var zip = currentBuffer.Zip(items, (op, result) => new { op, result });
foreach (var a in zip)
{
a.op.Response = a.result;
a.op.Cts.Cancel();
}
}
catch (Exception e)
{
foreach (var op in currentBuffer)
{
op.Error = e;
op.Cts.Cancel();
}
}
где Client
это IElasticClient
.
Поиск сообщения об исключении в Google приводит меня к этот метод в классе JsonSerializerInternalBase в JSON.Net, который, кажется, выполняется после каждой десериализации:
private ErrorContext GetErrorContext(object currentObject, object member, string path, Exception error)
{
if (_currentErrorContext == null)
{
_currentErrorContext = new ErrorContext(currentObject, member, path, error);
}
if (_currentErrorContext.Error != error)
{
throw new InvalidOperationException("Current error context error is different to requested error.");
}
return _currentErrorContext;
}
Учитывая, что один объект NEST повторно используется для каждой операции в нескольких потоках, и я думаю, что NEST использует только один экземпляр JsonSerializer, это заставляет меня думать, что эта часть JSON.Net не является потокобезопасной. Хотя странно, что ошибка появляется только через несколько часов после запуска.
Как я могу отладить это дальше?
JsonSerializerInternalBase
— это базовый класс дляJsonSerializerInternalWriter.cs
< /a> иJsonSerializerInternalReader.cs
неJsonSerializer
. Для каждого вызоваSerialize
,Deserialize
илиPopulate
JsonSerializer
выделяет один из них для выполнения фактической работы - вероятно, для безопасности потоков. - person dbc   schedule 21.12.2015serializer.Serialize()
, включая то, как инициализируетсяJsonSerializer.Error
? - person dbc   schedule 21.12.2015