Текущая ошибка контекста ошибки отличается от запрошенного исключения ошибки в Json.Net

Контекст

Я написал инфраструктуру параллельных заданий на 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 не является потокобезопасной. Хотя странно, что ошибка появляется только через несколько часов после запуска.

Как я могу отладить это дальше?


person rikkit    schedule 21.12.2015    source источник
comment
JsonSerializerInternalBase — это базовый класс для JsonSerializerInternalWriter.cs< /a> и JsonSerializerInternalReader.cs не JsonSerializer. Для каждого вызова Serialize, Deserialize или Populate JsonSerializer выделяет один из них для выполнения фактической работы - вероятно, для безопасности потоков.   -  person dbc    schedule 21.12.2015
comment
1) Эта трассировка выглядит неполной - она ​​не показывает никакой трассировки внутри самого Json.NET. Можете ли вы отредактировать вопрос, чтобы включить всю трассировку, включая все внутренние исключения? 2) Можете ли вы показать вызов serializer.Serialize(), включая то, как инициализируется JsonSerializer.Error ?   -  person dbc    schedule 21.12.2015
comment
1. Эта трассировка стека у меня есть. Блок кода из класса массового поиска копирует исключение и повторно генерируется в вызывающем потоке; Я предполагаю, что он теряет полную трассировку стека. Я изменю код, чтобы получить полную трассировку и запустить ее на ночь. 2. NEST создает свой собственный JsonSerializer, хотя это усложняется тем, что я использую собственный JsonConverter, который вызывает другой JsonSerializer. Здесь много кода, поэтому я подожду результатов повторного запуска, прежде чем начну форматировать его для StackOverflow. Спасибо за ваши вопросы   -  person rikkit    schedule 21.12.2015


Ответы (2)


Мой коллега в конце концов отследил ошибку - это произошло из-за того, что внутри JsonConverter было создано исключение, которое было вызвано другим JsonConverter. «Контекст ошибки» — это внутренняя вещь JSON.Net, используемая для отслеживания последнего сгенерированного исключения. Похоже, что исключение было обработано неправильным JsonConverter. Мы добавили флаг во внутренний JsonConverter, чтобы он знал, что исключение не должно вызываться в определенном контексте.

person rikkit    schedule 30.01.2017

Я столкнулся с этой ошибкой, когда свойство enum сериализовалось как null с помощью пользовательского сериализатора, а затем десериализовалось с помощью десериализатора по умолчанию.

person AndrewS    schedule 26.09.2019