如何在 ASP.net 核心中手动重启 BackgroundService
How to restart manually a BackgroundService in ASP.net core
我创建后台服务:
public class CustomService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
//...
}
}
我添加到项目中:
public class Startup
{
//...
public void ConfigureServices(IServiceCollection services)
{
services.AddHostedService<CustomService>();
//...
}
//...
}
如何从另一个 class 中找到 CustomService?
如何重新开始?
为调用 StartAsync 创建一个接口:
public interface ICustomServiceStarter
{
Task StartAsync(CancellationToken token = default);
}
public class CustomService : BackgroundService, ICustomServiceStarter
{
//...
Task ICustomServiceStarter.StartAsync(CancellationToken token = default) => base.StartAsync(token);
//...
}
将接口注册为单例:
public class Startup
{
//...
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddSingleton<ICustomServiceStarter, CustomService>();
}
//...
}
并在需要时注入 ICustomServiceStarter:
public class MyServiceControllerr : Controller
{
ICustomServiceStarter _starter;
public MyServiceController(ICustomServiceStarter starter)
{
_starter = starter;
}
[HttpPost]
public async Task<IActionResult> Start()
{
await _starter.StartAsync();
return Ok();
}
}
当谈到控制器的动作时,使用“await BackgroundService.StartAsync”是 long-running 任务的错误方式。
例如,主要用途可能是请求的超时取决于代理设置。
下面是一个如何使您的 BackgroundService 可重启的示例。
后台服务实现:
public class MyBackgroundService: BackgroundService
{
private volatile bool _isFinished = false;
private SemaphoreSlim _semaphore = new SemaphoreSlim(0,1);
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_isFinished = false;
// DoSomeWork
_isFinished = true;
await WaitToRestartTask(stoppingToken);
}
private async Task WaitToRestartTask(CancellationToken stoppingToken)
{
// wait until _semaphore.Release()
await _semaphore.WaitAsync(stoppingToken);
// run again
await base.StartAsync(stoppingToken);
}
public void RestartTask()
{
if (!_isFinished)
throw new InvalidOperationException("Background service is still working");
// enter from _semaphore.WaitAsync
_semaphore.Release();
}
}
控制器的操作(例如):
public async Task<IActionResult> Restart()
{
var myBackgroundService= _serviceProvider.GetServices<IHostedService>()
.OfType<MyBackgroundService>()
.First();
try
{
myBackgroundService.RestartTask();
return Ok($"MyBackgroundService was restarted");
}
catch (InvalidOperationException exception)
{
return BadRequest(exception.Message);
}
}
我创建后台服务:
public class CustomService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
//...
}
}
我添加到项目中:
public class Startup
{
//...
public void ConfigureServices(IServiceCollection services)
{
services.AddHostedService<CustomService>();
//...
}
//...
}
如何从另一个 class 中找到 CustomService?
如何重新开始?
为调用 StartAsync 创建一个接口:
public interface ICustomServiceStarter
{
Task StartAsync(CancellationToken token = default);
}
public class CustomService : BackgroundService, ICustomServiceStarter
{
//...
Task ICustomServiceStarter.StartAsync(CancellationToken token = default) => base.StartAsync(token);
//...
}
将接口注册为单例:
public class Startup
{
//...
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddSingleton<ICustomServiceStarter, CustomService>();
}
//...
}
并在需要时注入 ICustomServiceStarter:
public class MyServiceControllerr : Controller
{
ICustomServiceStarter _starter;
public MyServiceController(ICustomServiceStarter starter)
{
_starter = starter;
}
[HttpPost]
public async Task<IActionResult> Start()
{
await _starter.StartAsync();
return Ok();
}
}
当谈到控制器的动作时,使用“await BackgroundService.StartAsync”是 long-running 任务的错误方式。
例如,主要用途可能是请求的超时取决于代理设置。
下面是一个如何使您的 BackgroundService 可重启的示例。
后台服务实现:
public class MyBackgroundService: BackgroundService
{
private volatile bool _isFinished = false;
private SemaphoreSlim _semaphore = new SemaphoreSlim(0,1);
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_isFinished = false;
// DoSomeWork
_isFinished = true;
await WaitToRestartTask(stoppingToken);
}
private async Task WaitToRestartTask(CancellationToken stoppingToken)
{
// wait until _semaphore.Release()
await _semaphore.WaitAsync(stoppingToken);
// run again
await base.StartAsync(stoppingToken);
}
public void RestartTask()
{
if (!_isFinished)
throw new InvalidOperationException("Background service is still working");
// enter from _semaphore.WaitAsync
_semaphore.Release();
}
}
控制器的操作(例如):
public async Task<IActionResult> Restart()
{
var myBackgroundService= _serviceProvider.GetServices<IHostedService>()
.OfType<MyBackgroundService>()
.First();
try
{
myBackgroundService.RestartTask();
return Ok($"MyBackgroundService was restarted");
}
catch (InvalidOperationException exception)
{
return BadRequest(exception.Message);
}
}