We are seeing a steady memory growth on our Sitecore 8.2 update 1 application. We had AUTOFAC DI previously and have been completely replaced with Sitecore OOB MS DI.
We followed some guidance from blog post below in order to make sure that Pipeline Processors respects the Scoped lifetime. https://www.coreysmith.co/sitecore-dependency-injection-scoped-services/
RESULT:
The CPU is a lot better with the Sitecore OOB DI container. However, slight memory growth still exists.
I'm expecting that after a certain period of load test the memory should stabilize and should drop down once the load test is stopped. But it's not happening:
Memory Dump shows IDisposable collection holding lots of SitecoreRequestScopeModule. _transientDisposables private collection of Microsoft.Extensions.DependencyInjection.ServiceProvider class
Service Configuration:
public void Configure(IServiceCollection serviceCollection)
{
//For getting a SitecoreService for any database
serviceCollection.AddSingleton<Func<Database, ISitecoreService>>(_ => CreateSitecoreService);
serviceCollection.AddScopedWithFuncFactory<ISitecoreService>(_ => CreateSitecoreContextService());
serviceCollection.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()
.Where(assembly => assembly.GetName().Name.Contains("Digital")).ToArray());
serviceCollection.AddScopedWithFuncFactory<ILoggerService>(c => new LoggerService(_Constants.WebLoggerName));
}
private static T Get<T>()
{
return ServiceLocator.ServiceProvider.GetService<T>();
}
private static ISitecoreService CreateSitecoreContextService()
{
var sitecoreServiceThunk = Get<Func<Database, ISitecoreService>>();
return sitecoreServiceThunk(global::Sitecore.Context.Database);
}
private static ISitecoreService CreateSitecoreService(Database database)
{
return new SitecoreService(database);
}
Pipeline Processor Injection:
public class AssignQuotationSession : RequestBeginProcessor
{
protected readonly Func<ILoggerService> _scopeLoggerService;
private readonly Func<ISitecoreService> _scopeSitecoreService;
public AssignQuotationSession(Func<ILoggerService> loggerService, Func<ISitecoreService> SitecoreService)
{
_scopeLoggerService = loggerService;
_scopeSitecoreService = SitecoreService;
}
public override void Process(RequestBeginArgs args)
{
Assert.ArgumentNotNull(args, "args");
var loggerService = _scopeLoggerService();
var sitecoreService = _scopeSitecoreService();
....
}
}
Sitecore Service that wraps Glass SitecoreService
public class SitecoreService : IContentService, IDisposable
{
private readonly ISitecoreService _context;
/// <summary>
/// Initializes a new instance of the <see cref="SitecoreRepository"/> class.
/// </summary>
/// <param name="context">Sitecore context.</param>
public SitecoreService(ISitecoreService context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
this._context = context;
}
public TModel GetEntity<TModel>(string identity) where TModel : class
{
return this._context.GetItem<TModel>(identity);
}
public void Dispose()
{
_context.Dispose();
}
}
Any suggestion on what we may be doing wrong here?
This thread talks about the potential cause:
https://github.com/aspnet/AspNetCore/issues/5496
https://github.com/aspnet/DependencyInjection/issues/456
Not too sure if we need to create a scope first and wrap it in a using
statement. I've been told that SitecoreRequestScopeModule
will do all cleanup. But it doesn't look like it...