在每个请求范围

时间:2018-04-04 12:21:59

标签: c# memory-management dependency-injection asp.net-core-webapi business-logic

我的后台服务在我的ASP .NET Core WebApi应用程序中每30秒运行一次。它通过行

注册到Startup.cs中ConfigureServices中的服务容器
services.AddSingleton<IHostedService, SimpleService>();

然后我让这个类及其上层每30秒执行一个给定的方法:

一般后台服务类:

public abstract class BackgroundService : IHostedService, IDisposable
{
    private Task currentTask;
    private readonly CancellationTokenSource stopCts = new CancellationTokenSource();

    public virtual Task StartAsync(CancellationToken cancellationToken)
    {
        currentTask = ExecuteAsync(stopCts.Token);

        if (currentTask.IsCompleted)
            return currentTask;

        return Task.CompletedTask;
    }

    public virtual async Task StopAsync(CancellationToken cancellationToken)
    {
        if (currentTask == null)
            return;

        try
        {
            stopCts.Cancel();
        }
        finally
        {
            await Task.WhenAny(currentTask, Task.Delay(Timeout.Infinite, cancellationToken));
        }
    }

    protected virtual async Task ExecuteAsync(CancellationToken cancellationToken)
    {
        DateTime nextExecution = DateTime.Now;

        do
        {
            DateTime currentTime = DateTime.Now;

            if (nextExecution <= currentTime)
            {
                nextExecution = currentTime.Add(TimeSpan.FromSeconds(30));
                await Process(cancellationToken);
            }
            else
            {
                await Task.Delay(nextExecution - currentTime, cancellationToken);
            }
        }
        while (!cancellationToken.IsCancellationRequested);
    }

    protected abstract Task Process(CancellationToken cancellationToken);

    public void Dispose()
    {
        stopCts.Cancel();
    }
}

需要特定范围时使用的那个:

public abstract class ScopedBackgroundService : BackgroundService
{
    private readonly IServiceScopeFactory serviceScopeFactory;

    public ScopedBackgroundService(IServiceScopeFactory serviceScopeFactory)
    {
        this.serviceScopeFactory = serviceScopeFactory;
    }

    protected override async Task Process(CancellationToken cancellationToken)
    {
        using (var scope = serviceScopeFactory.CreateScope())
        {
            await ProcessInScope(scope.ServiceProvider, cancellationToken);
        }
    }

    public abstract Task ProcessInScope(IServiceProvider serviceProvider, CancellationToken cancellationToken);
}

实现服务本身时,我使用此类(也在ConfigureServices方法中注册):

public class SimpleService : ScopedBackgroundService
{
    private ISimpleBusiness simpleBusiness;

    public SimpleService(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory)
    {
    }

    public override async Task ProcessInScope(IServiceProvider serviceProvider, CancellationToken cancellationToken)
    {
        this.simpleBusiness = serviceProvider.GetService<ISimpleBusiness>();

        foreach (var b in simpleBusiness.GetAll())
        {
            await this.simpleBusiness.Check(b);
        }
    }
}

这很好用。但我有一个问题,即每次请求后使用的内存增加了。垃圾收集器也没有被触发。过了一段时间,在某些情况下我无法检测/发现内存在大约20毫秒内迅速增加,最多可达150 MB。

SimpleBusiness类(实现接口ISimpleBusiness)使用通过构造函数注入获得的simpleDA中的db上下文:

public class SimpleBusiness : ISimpleBusiness
{
    private ISimpleDA simpleDA;
    private IHostingEnvironment hostingEnvironment;
    ...

    public SimpleBusiness(ISimpleDA simpleDA, IHostingEnvironment environment, ...)
    {
        this.simpleDA = simpleDA;
        this.hostingEnvironment = environment;
        ...
    }
    ...

我猜这个dbcontext及其附加对象不会从内存中处理/删除。在ScopedBackgroundService中调用ProcessInScope时,如何在不更改当前数据访问和业务类/接口的情况下为底层方法中使用的所有对象创建实例时,如何将请求生命周期范围中的db上下文传递给构造函数?

编辑:

这是大约26分钟的内存和CPU使用率。

The usage of about 26 minutes runtime

0 个答案:

没有答案