Azure 函数在 "stress test" 中抛出 SimpleInjector.ActivationException
Azure Function throws SimpleInjector.ActivationException in "stress test"
我们在一个基于消费计划的函数应用程序中有几个函数。当我使用 JMeter(同时 200 个线程)对这些函数进行压力测试时,这些函数在大约 50% 的时间内抛出 SimpleInjector.ActivationException。并非所有请求都失败。
我不明白为什么这只是部分请求。
调用堆栈:
2021-07-06T08:43:41.159 [错误] Er is een probleem opgetreden
SimpleInjector.ActivationException : GetLocalKeyDataByDateQueryHandler 类型的构造函数包含名称为 'queryValidator' 且类型为 IValidator 的参数,但 IValidator 未注册。要解析 IValidator,必须在 container.at SimpleInjector.Container.ThrowParameterTypeMustBeRegistered(InjectionTargetInfo target)at SimpleInjector.Advanced.DefaultDependencyInjectionBehavior.GetInstanceProducer(InjectionConsumerInfo dependency,Boolean throwOnFailure)at SimpleInjector.ContainerOptions.GetInstanceProducerFor(InjectionConsumerInfo consumer)at 注册SimpleInjector.Registration.BuildConstructorParameters(ConstructorInfo constructor)at SimpleInjector.Registration.BuildNewExpression()at SimpleInjector.Registration.BuildTransientExpression()at SimpleInjector.Registration.BuildTransientDelegate()at SimpleInjector.Lifestyles.ScopedRegistration.BuildExpression()at SimpleInjector.InstanceProducer.BuildExpressionInternal()at SimpleInjector.Internals.LazyEx`1.InitializeAndReturn() 在 SimpleInjector.InstanceProducer.BuildInstanceCreator() 在 SimpleInjector.InstanceProducer.BuildAndReplaceInstanceCreatorAndCreateFirstInstance() 在 SimpleInjector.InstanceProducer.GetInstance() 在 SimpleInjector.Container.GetInstanceTServiceat 异步 ProRail。PUIC2.Web.Functions.GetPuicDataByChangeDate.Run(GetPuicDataByDate inputParams、ILogger 记录器、ExecutionContext 上下文) 在 D:\a\s\Src\Web\ProRail.PUIC2.Web.Functions\Functions\GetPuicDataByChangeDate.cs : 35
函数:
public class GetPuicDataByLocalKey
{
[FunctionName("GetPuicDataByLocalKey")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]
Models.GetPuicDataByLocalKey queryInput, ILogger logger, ExecutionContext context)
{
var container = DependencyInjection.GetContainerInstance(context);
await using (AsyncScopedLifestyle.BeginScope(container))
{
var loggingUtils = container.GetInstance<ILoggingUtils>();
try
{
logger.LogTrace(loggingUtils.MethodBegin);
container.GetInstance<Configuration.ILoggerFactory>().SetLogger(logger);
var queryHandler = container.GetInstance<IQueryHandler<GetPuicDataQuery, IEnumerable<PuicData>>>();
var results = await queryHandler.Handle(new GetPuicDataQuery
{
Source = queryInput.Source,
DateValid = queryInput.DateValid,
LocalKeyValues = queryInput.LocalKeyValues.Select(lkv => new Core.Entities.Data.KeyValue
{
Key = lkv.Key,
Value = lkv.Value
})
});
if (results == null)
{
return new JsonResult(Enumerable.Empty<Models.PuicData>());
}
// Get local keys grouped by Puic
var puicDataList = results.GroupBy(l => l.Puic).Select(g => PuicDataConverter.Convert(g));
return new JsonResult(puicDataList);
}
catch (PuicException e)
{
logger.LogError(e, "Data is waarschijnlijk niet goed");
return new BadRequestErrorMessageResult(e.Message);
}
catch (Exception e)
{
logger.LogError(e, "Er is een probleem opgetreden");
return new InternalServerErrorResult();
}
finally
{
logger.LogTrace(loggingUtils.MethodEnd);
}
}
}
}
容器配置
public static class DependencyInjection
{
private static Container containerInstance = null;
public static Container GetContainerInstance(ExecutionContext context)
{
if (containerInstance == null)
{
containerInstance = new Container();
containerInstance.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
InitializeConfiguration(containerInstance, context);
RegisterSimpleTypes(containerInstance);
RegisterQueryHandlers(containerInstance);
RegisterCommandHandlers(containerInstance);
RegisterValidators(containerInstance);
RegisterDatabaseTypes(containerInstance);
}
return containerInstance;
}
[...]
private static void RegisterQueryHandlers(Container container)
{
var businessLogicAssembly = typeof(GetUsersQuery).Assembly;
container.Register(typeof(IQueryHandler<,>), businessLogicAssembly, Lifestyle.Scoped);
}
[...]
}
您的代码似乎存在多线程问题; DependencyInjection.GetContainerInstance
方法。
GetContainerInstance
可能会在并行调用时创建多个 Container
实例,最终 Container
实例的配置将不确定。
要解决此问题,您必须同步容器的创建。有很多方法可以做到这一点,但您可以试试这个:
public static Container GetContainerInstance(ExecutionContext context)
{
// Double-checked lock. Ensures only one Container instance
// is created.
if (containerInstance is null)
{
lock (typeof(DependencyInjection))
{
if (containerInstance is null)
{
containerInstance = BuildContainer();
}
}
}
return containerInstance;
}
private static Container BuildContainer()
{
var container = new Container();
container.Options.DefaultScopedLifestyle =
new AsyncScopedLifestyle();
InitializeConfiguration(container, context);
RegisterSimpleTypes(container);
RegisterQueryHandlers(container);
RegisterCommandHandlers(container);
RegisterValidators(container);
RegisterDatabaseTypes(container);
return container;
}
我们在一个基于消费计划的函数应用程序中有几个函数。当我使用 JMeter(同时 200 个线程)对这些函数进行压力测试时,这些函数在大约 50% 的时间内抛出 SimpleInjector.ActivationException。并非所有请求都失败。
我不明白为什么这只是部分请求。
调用堆栈:
2021-07-06T08:43:41.159 [错误] Er is een probleem opgetreden
SimpleInjector.ActivationException : GetLocalKeyDataByDateQueryHandler 类型的构造函数包含名称为 'queryValidator' 且类型为 IValidator 的参数,但 IValidator 未注册。要解析 IValidator,必须在 container.at SimpleInjector.Container.ThrowParameterTypeMustBeRegistered(InjectionTargetInfo target)at SimpleInjector.Advanced.DefaultDependencyInjectionBehavior.GetInstanceProducer(InjectionConsumerInfo dependency,Boolean throwOnFailure)at SimpleInjector.ContainerOptions.GetInstanceProducerFor(InjectionConsumerInfo consumer)at 注册SimpleInjector.Registration.BuildConstructorParameters(ConstructorInfo constructor)at SimpleInjector.Registration.BuildNewExpression()at SimpleInjector.Registration.BuildTransientExpression()at SimpleInjector.Registration.BuildTransientDelegate()at SimpleInjector.Lifestyles.ScopedRegistration.BuildExpression()at SimpleInjector.InstanceProducer.BuildExpressionInternal()at SimpleInjector.Internals.LazyEx`1.InitializeAndReturn() 在 SimpleInjector.InstanceProducer.BuildInstanceCreator() 在 SimpleInjector.InstanceProducer.BuildAndReplaceInstanceCreatorAndCreateFirstInstance() 在 SimpleInjector.InstanceProducer.GetInstance() 在 SimpleInjector.Container.GetInstanceTServiceat 异步 ProRail。PUIC2.Web.Functions.GetPuicDataByChangeDate.Run(GetPuicDataByDate inputParams、ILogger 记录器、ExecutionContext 上下文) 在 D:\a\s\Src\Web\ProRail.PUIC2.Web.Functions\Functions\GetPuicDataByChangeDate.cs : 35
函数:
public class GetPuicDataByLocalKey
{
[FunctionName("GetPuicDataByLocalKey")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)]
Models.GetPuicDataByLocalKey queryInput, ILogger logger, ExecutionContext context)
{
var container = DependencyInjection.GetContainerInstance(context);
await using (AsyncScopedLifestyle.BeginScope(container))
{
var loggingUtils = container.GetInstance<ILoggingUtils>();
try
{
logger.LogTrace(loggingUtils.MethodBegin);
container.GetInstance<Configuration.ILoggerFactory>().SetLogger(logger);
var queryHandler = container.GetInstance<IQueryHandler<GetPuicDataQuery, IEnumerable<PuicData>>>();
var results = await queryHandler.Handle(new GetPuicDataQuery
{
Source = queryInput.Source,
DateValid = queryInput.DateValid,
LocalKeyValues = queryInput.LocalKeyValues.Select(lkv => new Core.Entities.Data.KeyValue
{
Key = lkv.Key,
Value = lkv.Value
})
});
if (results == null)
{
return new JsonResult(Enumerable.Empty<Models.PuicData>());
}
// Get local keys grouped by Puic
var puicDataList = results.GroupBy(l => l.Puic).Select(g => PuicDataConverter.Convert(g));
return new JsonResult(puicDataList);
}
catch (PuicException e)
{
logger.LogError(e, "Data is waarschijnlijk niet goed");
return new BadRequestErrorMessageResult(e.Message);
}
catch (Exception e)
{
logger.LogError(e, "Er is een probleem opgetreden");
return new InternalServerErrorResult();
}
finally
{
logger.LogTrace(loggingUtils.MethodEnd);
}
}
}
}
容器配置
public static class DependencyInjection
{
private static Container containerInstance = null;
public static Container GetContainerInstance(ExecutionContext context)
{
if (containerInstance == null)
{
containerInstance = new Container();
containerInstance.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
InitializeConfiguration(containerInstance, context);
RegisterSimpleTypes(containerInstance);
RegisterQueryHandlers(containerInstance);
RegisterCommandHandlers(containerInstance);
RegisterValidators(containerInstance);
RegisterDatabaseTypes(containerInstance);
}
return containerInstance;
}
[...]
private static void RegisterQueryHandlers(Container container)
{
var businessLogicAssembly = typeof(GetUsersQuery).Assembly;
container.Register(typeof(IQueryHandler<,>), businessLogicAssembly, Lifestyle.Scoped);
}
[...]
}
您的代码似乎存在多线程问题; DependencyInjection.GetContainerInstance
方法。
GetContainerInstance
可能会在并行调用时创建多个 Container
实例,最终 Container
实例的配置将不确定。
要解决此问题,您必须同步容器的创建。有很多方法可以做到这一点,但您可以试试这个:
public static Container GetContainerInstance(ExecutionContext context)
{
// Double-checked lock. Ensures only one Container instance
// is created.
if (containerInstance is null)
{
lock (typeof(DependencyInjection))
{
if (containerInstance is null)
{
containerInstance = BuildContainer();
}
}
}
return containerInstance;
}
private static Container BuildContainer()
{
var container = new Container();
container.Options.DefaultScopedLifestyle =
new AsyncScopedLifestyle();
InitializeConfiguration(container, context);
RegisterSimpleTypes(container);
RegisterQueryHandlers(container);
RegisterCommandHandlers(container);
RegisterValidators(container);
RegisterDatabaseTypes(container);
return container;
}