Location
- File:
src/ModularPipelines/Engine/ModuleContextProvider.cs
- Lines: 10, 17-23
Problem
The ModuleContextProvider class maintains a list of service scopes that are never disposed:
private readonly List<IServiceScope> _scopes = new();
public IPipelineContext GetModuleContext()
{
var serviceScope = _serviceProvider.CreateAsyncScope();
_scopes.Add(serviceScope);
return serviceScope.ServiceProvider.GetRequiredService<IPipelineContext>();
}
Why it's a problem
- Potential Resource Leak: Service scopes are added to the list but there's no clear disposal mechanism
- Memory Growth: The list grows unbounded during pipeline execution
- IScopeDisposer Interface: While the class implements
IScopeDisposer, the GetScopes() method only returns the scopes - it doesn't dispose them
- Thread Safety: The List is not thread-safe, but
GetModuleContext() could be called from multiple threads
Suggested Fix
- Make the class implement
IDisposable or IAsyncDisposable
- Dispose all scopes when the provider is disposed
- Use a thread-safe collection like
ConcurrentBag<IServiceScope>
internal class ModuleContextProvider : IPipelineContextProvider, IScopeDisposer, IAsyncDisposable
{
private readonly IServiceProvider _serviceProvider;
private readonly ConcurrentBag<IServiceScope> _scopes = new();
// ...
public async ValueTask DisposeAsync()
{
foreach (var scope in _scopes)
{
if (scope is IAsyncDisposable asyncDisposable)
await asyncDisposable.DisposeAsync();
else
scope.Dispose();
}
}
}
Category