我的后台服务在我的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使用率。