如何在 ASPNET Core 3.0 中启动后台进程?
How do you launch a background process in ASPNET Core 3.0?
我知道新的 ASPNET Core 3.0 堆栈在托管进程方面有很多改进。
我很好奇能够从 Razor PageModel 定义和执行后台进程的最佳方式?这意味着我有一些逻辑需要在后台启动一些东西,然后 Razor 页面不需要监视它的结果,但如果这不是太难的话,我也希望能够观察它。
谁能给我看代码示例或指出正确的方向?
因为这可能是您 的后续行动,我假设您希望在您的 ASP.NET 核心应用程序中拥有一些后台服务(作为托管服务)能够执行后台任务。现在您想通过控制器或 Razor 页面操作触发这样的任务并让它在后台执行吗?
一个常见的模式是拥有一些中央存储来跟踪后台服务和 Web 应用程序都可以访问的任务。一种简单的方法是使其成为双方都可以访问的(线程安全的)单例服务。
文档实际上显示了一个使用 BackgroundTaskQueue
的简单示例,这正是共享的 service/state。不过,如果您有一名工人从事特定类型的工作,您也可以这样实施:
public class JobQueue<T>
{
private readonly ConcurrentQueue<T> _jobs = new ConcurrentQueue<T>();
private readonly SemaphoreSlim _signal = new SemaphoreSlim(0);
public void Enqueue(T job)
{
_jobs.Enqueue(job);
_signal.Release();
}
public async Task<T> DequeueAsync(CancellationToken cancellationToken = default)
{
await _signal.WaitAsync(cancellationToken);
_jobs.TryDequeue(out var job);
return job;
}
}
然后您可以使用服务集合注册此实现以及在此队列上运行的托管后台服务:
services.AddSingleton<JobQueue<MyJob>>();
services.AddHostedService<MyJobBackgroundService>();
该托管服务的实现可能如下所示:
public class MyJobBackgroundService : BackgroundService
{
private readonly ILogger<MyJobBackgroundService> _logger;
private readonly JobQueue<MyJob> _queue;
public MyJobBackgroundService(ILogger<MyJobBackgroundService> logger, JobQueue<MyJob> queue)
{
_logger = logger;
_queue = queue;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var job = await _queue.DequeueAsync(stoppingToken);
// do stuff
_logger.LogInformation("Working on job {JobId}", job.Id);
await Task.Delay(2000);
}
}
}
在控制器操作或 Razor 页面模型中,您只需注入 JobQueue<MyJob>
然后对其调用 Enqueue
即可将作业添加到列表中。一旦后台服务准备好处理它,它就会处理它。
最后请注意,队列显然在内存中,因此如果您的应用程序关闭,待办任务列表也会消失。如果需要,您当然也可以将此信息保存在数据库中,并从数据库中设置队列。
我知道新的 ASPNET Core 3.0 堆栈在托管进程方面有很多改进。
我很好奇能够从 Razor PageModel 定义和执行后台进程的最佳方式?这意味着我有一些逻辑需要在后台启动一些东西,然后 Razor 页面不需要监视它的结果,但如果这不是太难的话,我也希望能够观察它。
谁能给我看代码示例或指出正确的方向?
因为这可能是您
一个常见的模式是拥有一些中央存储来跟踪后台服务和 Web 应用程序都可以访问的任务。一种简单的方法是使其成为双方都可以访问的(线程安全的)单例服务。
文档实际上显示了一个使用 BackgroundTaskQueue
的简单示例,这正是共享的 service/state。不过,如果您有一名工人从事特定类型的工作,您也可以这样实施:
public class JobQueue<T>
{
private readonly ConcurrentQueue<T> _jobs = new ConcurrentQueue<T>();
private readonly SemaphoreSlim _signal = new SemaphoreSlim(0);
public void Enqueue(T job)
{
_jobs.Enqueue(job);
_signal.Release();
}
public async Task<T> DequeueAsync(CancellationToken cancellationToken = default)
{
await _signal.WaitAsync(cancellationToken);
_jobs.TryDequeue(out var job);
return job;
}
}
然后您可以使用服务集合注册此实现以及在此队列上运行的托管后台服务:
services.AddSingleton<JobQueue<MyJob>>();
services.AddHostedService<MyJobBackgroundService>();
该托管服务的实现可能如下所示:
public class MyJobBackgroundService : BackgroundService
{
private readonly ILogger<MyJobBackgroundService> _logger;
private readonly JobQueue<MyJob> _queue;
public MyJobBackgroundService(ILogger<MyJobBackgroundService> logger, JobQueue<MyJob> queue)
{
_logger = logger;
_queue = queue;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
var job = await _queue.DequeueAsync(stoppingToken);
// do stuff
_logger.LogInformation("Working on job {JobId}", job.Id);
await Task.Delay(2000);
}
}
}
在控制器操作或 Razor 页面模型中,您只需注入 JobQueue<MyJob>
然后对其调用 Enqueue
即可将作业添加到列表中。一旦后台服务准备好处理它,它就会处理它。
最后请注意,队列显然在内存中,因此如果您的应用程序关闭,待办任务列表也会消失。如果需要,您当然也可以将此信息保存在数据库中,并从数据库中设置队列。