Фантомное исключение останавливает выполнение дочернего метода, но не всплывает - PullRequest
0 голосов
/ 26 сентября 2018

У меня есть лямбда-функция AWS, которая выполняется в ответ на сообщение SNS.Существует некоторое необъяснимое поведение, когда выполнение внезапно останавливается в дочернем методе (как будто генерируется исключение), но потом родитель продолжает работать как обычно.

public void InsertEntity(Entity entity)
{
    _context.Entities.Add(entity);

    _logger.Log($"Before SaveChanges, entity.Id is {entity.Id}");

    _context.SaveChanges();

    _logger.Log($"After SaveChanges, entity.Id is {entity.Id}");

    if (entity.Id < 0)
        throw new Exception($"InsertEntity succeeded, but id is invalid: {entity.Id}");
}

public int? ImportEntity(string xml)
{
    var entity = new Entity(xml);

    _entityRepository.InsertEntity(entity);

    _logger.LogLine($"Entity inserted successfully with Id {entity.Id}");

    return entity.Id;
}

Контекст в этом случае является стандартным DbContext, использующимпровайдер PostgreSQL EF.

Когда объект создается впервые, идентификатор равен 0. Когда вы добавляете его в контекст DbSet, идентификатор становится временным отрицательным целым числом, таким как -2147392341.После вызова SaveChanges объект должен получить Id из базы данных, положительное число.

Любые исключения здесь должны появляться в методе, который вызывает ImportEntity, и он должен обрабатывать ошибку.Вместо этого мой файл журнала в AWS выглядит следующим образом:

Before SaveChanges, entity.Id is -2147482647
Entity inserted successfully with Id -2147482647

И возвращается отрицательное значение без исключения в любой точке.Поскольку у меня есть код внутри InsertEntity, который специально проверяет наличие отрицательного значения, я вижу только одну возможность - SaveChanges выдает исключение, которое приводит к тому, что и регистрация, и отрицательная проверка не запускаются.Но как родительский метод продолжает регистрировать, выполнять и возвращать значение?

Я знаю, что мой код обновляется в AWS, потому что я недавно добавил журналирование "Before SaveChanges", и оно отображается, и я добавил регистрациювсе одновременно.

РЕДАКТИРОВАТЬ :

Я добавил try / catch непосредственно вокруг _context.SaveChanges(); и смог отловить основное исключение.Остается вопрос: почему / как можно продолжить выполнение в функции ImportEntity, даже если исключение выдается из InsertEntity.

EDIT 2 :

Добавление определения csproj:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <AssemblyName>MyService</AssemblyName>
    <OutputType>Library</OutputType>
    <PackageId>MyService</PackageId>
    <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
    <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
    <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
    <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
    <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
    <GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
    <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
    <GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
</PropertyGroup>
<ItemGroup>
    <None Update="runtimes\linux\lib\netstandard1.3\System.Net.NetworkInformation.dll">
    <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    </None>
</ItemGroup>
<ItemGroup>
    <PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" />
    <PackageReference Include="AWSSDK.S3" Version="3.3.16.2" />
    <PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.1.0" />
    <PackageReference Include="Amazon.Lambda.S3Events" Version="1.0.2" />
    <PackageReference Include="AWSSDK.XRay" Version="3.3.1.6" />
    <PackageReference Include="AWSXRayRecorder" Version="2.0.0-beta" />
    <PackageReference Include="AWSXRayRecorder.Handlers.AwsSdk" Version="2.0.0-beta" />
    <PackageReference Include="Castle.Core" Version="4.2.1" />
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="2.0.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.0.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.0.0" />
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="2.0.1" />
    <PackageReference Include="HtmlAgilityPack.NetCore" Version="1.5.0.1" />
    <PackageReference Include="Amazon.Lambda.SNSEvents" Version="1.0.0" />
    <PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.1" />
    <PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.2.0" />
    <PackageReference Include="AWSSDK.SimpleNotificationService" Version="3.3.0.24" />
</ItemGroup>
<ItemGroup>
    <DotNetCliToolReference Include="Amazon.Lambda.Tools" Version="2.1.0" />
</ItemGroup>
</Project>

И лямбда-метод верхнего уровня, который вызывается AWS, а при вызове вызывает ImportEntity:

public void ProcessEntity(SNSEvent evnt, ILambdaContext context)
{
    var fileContent = GetFileContent(evnt);

    using (var lifetimeScope = Container.BeginLifetimeScope())
    {
        var processor = processingScope.Resolve<IEntityProcessor>();
        var result = processor.ImportEntity(fileContent);

        context.Logger.LogLine($"Successfully imported entity, Id is {result.Value}");
        return result;
    }
}

1 Ответ

0 голосов
/ 08 октября 2018

Эта проблема встречалась много раз.Я подозреваю, что основная причина похожа на то, что происходит, когда незапланированный асинхронный процесс генерирует исключения: они не всплывают в вашем коде, потому что они не предназначены для этого.

В других случаях, когда подобные вещи были устранены, ошибка root обычно является внешней по отношению к вашему коду, то есть где-то в соединении с базой данных, сопоставлении или даже на самой стороне базы данных.Когда это происходит, поток просто умирает, и выполнение продолжается, как если бы SaveChanges возвращался нормально.

Тайм-аут базы данных может вызвать это поведение.Это может вызвать что-то вроде файла POCO, который не соответствует базе данных, и вы, скорее всего, не получите предупреждение.Это может привести к путанице между 32-битным и 64-битным расположением файлов.Если база данных является транзакционной и грязные объекты ObjectStateEntry не могут быть сохранены, сбой любой транзакции приведет к этому.

Я бы начал с просмотра журналов ошибок в вашей базе данных - удивительно, как часто проблема становится очевидной, когда вы делаете это.Если журналы не показывают проблему, поместите инструментарий на стороне базы данных и посмотрите на полученный запрос, результат запроса и его выполнение.Скорее всего, это укажет вам правильное направление.

Если это не разблокирует вас, то стоит потратить время на создание полного и выполнимого минимального репро и его публикацию.Это дало бы мне то, что мне нужно, чтобы отследить источник проблемы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...