Web应用程序本身的机制并不适合用来作为执行需要长时程运行的需求,而这类需求却很常见,而常见的解决方式是
第1种方式并不是一种正确的解决方式,严格来说不应该这样做。
第2种方式很容易达成,但有个缺点,使用者无法得知执行时的状态,因此无法确认到底是失败了还是仍然在执行中,这个问题可以透过一些设计解决,但都非常复杂。
目前在Asp.Net Core已经提供了「托管服务」IHostedService,可以解决Web本身不适合做为长时程执行的问题,然而单靠「托管服务」要实现整体的完整机制并不容易,而Quaerz.Net这个老牌的排程程序库能弭补这个问题,目前新版的Quaerz.Net 3已与Asp.Net Core已有很好的整合。
底下教学目标达成下列需求
完整的程序可由此下载
首先透过nuget将Quartz.Net引用至专案
Install-Package Quartz.AspNetCore
修改Startup.cs加入Quartz.Net的初始化相关程序
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddQuartz(q =>
{
q.UseMicrosoftDependencyInjectionScopedJobFactory();
q.UseSimpleTypeLoader();
q.UseInMemoryStore();
q.UseDefaultThreadPool(tp =>
{
tp.MaxConcurrency = 10;
});
var jobKey = DemoJob.JobKey;
q.AddJob<DemoJob>(jobKey, j => j
.StoreDurably()
.WithDescription("demo job")
);
});
// ASP.NET Core hosting
services.AddQuartzServer(options =>
{
options.WaitForJobsToComplete = true;
});
}
这里为了展示只简单的使用一些基本配置,想要更深入的了解Quartz.Net可以参考官方的quick start。
上面程序中有个地方须注意因为这边的DemoJob并没有关联到任何的Trigger,Quartz.Net预设情况下会自动删除因而会出现错误,因此要加上StoreDurably()。
撰写Job
public class DemoJob : IJob
{
public readonly static JobKey JobKey = new JobKey(nameof(DemoJob), JobKey.DefaultGroup);
public async Task Execute(IJobExecutionContext context)
{
await Task.Run(() =>
{
for (var i = 0; i < 5; i++)
{
var message = $"第{i}次执行";
Console.WriteLine(message);
context.Result = message;
context.CancellationToken.WaitHandle.WaitOne(TimeSpan.FromSeconds(5));
}
}, context.CancellationToken);
}
}
DemoJob作为展示,单纯的透过Console.WriteLine输出执行状态到Asp.Net core的Host上,因此如果使用IIS作为Host画面上是不会看到任何输出,所以记得要切换至专案作为Host
上面程序中的context.Result为Quartz.Net中提供的回报执行状态机制,後面我们会透过这个参数来取得目前Job中的执行状态,其物件形态为Object也就是说可以自定义想需要的内容,这边单纯的字串来回报。
新增TaskController与NewTask方法,用来建立Task的Trigger,让UI触发执行。
public async Task<IActionResult> NewTask([FromServices] ISchedulerFactory schedulerFactory, CancellationToken cancellationToken)
{
var scheduler = await schedulerFactory.GetScheduler(cancellationToken);
var trigger = TriggerBuilder.Create()
.ForJob(DemoJob.JobKey)
.StartNow()
.WithSimpleSchedule(x => x.WithRepeatCount(0))
.Build();
await scheduler.ScheduleJob(trigger);
return RedirectToAction("ExecutingJobs");
}
因为Quartz.Net本身目的是排程功能,而我们希望的Task只是单纯的执行一次,因此Trigger使用Simple并且设定WithRepeatCount为0,那麽Trigger执行後即会被Quartz.Net删除。
最後提供一个UI用来显示目前执行中的状态
public async Task<IActionResult> ExecutingJobs([FromServices] ISchedulerFactory schedulerFactory, CancellationToken cancellationToken)
{
var scheduler = await schedulerFactory.GetScheduler();
var executingJobs = await scheduler.GetCurrentlyExecutingJobs(cancellationToken);
var data = executingJobs.Select(x => new JobExecutionContextModel(x));
return View(data);
}
这样就简单快速的完成了一个可以在WEB长时程执行的机制并且能够有UI反馈
当然Quartz.Net能做的不止於此,譬如说执行中的Task允许取消机制,实现如Windows排程功能,并且可以让使用透过UI来操作,集群机制等等。
<<: ASUS Zenfone 3 Android 8.0.0 绕过 Google FRP
其实google的话就会有很多相关自然语言处理的定义与文章,自然语言处理英文为Natural Lan...
今天笔者想聊聊TensorFlow的矩阵运算模式,笔者向来的数学都不是太好,此次30天的尾声想要与大...
第一篇记录了时间序列属性,将趋势、季节性等元素拆解、分别画出图表; 第二篇则介绍时间序列转换方法,透...
终於完赛了!最近跑去画画,附上一幅《小王子与小狐狸》,小王子里面,最喜欢的就是他们的故事,是说画画...
今天我们继续介绍一些比较知名的AI作曲的公司/软件。 Jukedeck Jukedeck可以说是AI...