【发布时间】:2017-11-01 00:19:35
【问题描述】:
我正在尝试从 .NET 核心中的 Web API 控制器构建触发器 Quartz 作业。 我已经成功地通过 Startup 类的简单时间表创建了一个触发器:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider services)
{
loggerFactory.AddConsole(this.Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseCors("CorsPolicy");
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseMvc();
ProcessTracksScheduler.Start(services);
}
这里是启动方法:
public static class ProcessTracksScheduler
{
public static void Start(IServiceProvider provider)
{
try
{
ISchedulerFactory schedFact = new StdSchedulerFactory();
IScheduler sched = schedFact.GetScheduler();
sched.Start();
IJobDetail job = JobBuilder.Create<ProcessTracksJob>()
.WithIdentity("ProcessTracks", "Group1")
.Build();
job.JobDataMap["tracksService"] = provider.GetService(typeof(ITracksService));
job.JobDataMap["cloudService"] = provider.GetService(typeof(ICloudService));
job.JobDataMap["broadcastService"] = provider.GetService(typeof(IBroadcastService));
job.JobDataMap["categoriesService"] = provider.GetService(typeof(ICategoriesService));
ITrigger trigger = TriggerBuilder.Create()
.WithSimpleSchedule(x => x
.RepeatForever()
.WithInterval(TimeSpan.FromDays(1)))
.StartNow()
.Build();
sched.ScheduleJob(job, trigger);
}
catch (ArgumentException e)
{
// Log the error
}
}
}
还有工作:
public async void Execute(IJobExecutionContext context)
{
var tracksService = context.MergedJobDataMap["tracksService"] as ITracksService;
var cloudService = context.MergedJobDataMap["cloudService"] as ICloudService;
var broadcastService = context.MergedJobDataMap["broadcastService"] as IBroadcastService;
var categoryService = context.MergedJobDataMap["categoriesService"] as ICategoriesService;
if (tracksService == null || cloudService == null || broadcastService == null || categoryService == null)
return;
var broadcasts = broadcastService.GetAll();
// Some more work to do.
}
所以这个按预期工作,我很满意!但这里的问题是,当我试图构建一个触发器以使该作业仅从我的 Web API 控制器启动一次时:
[Route("Proccess")]
[HttpPost]
public async Task<IActionResult> ProccessTracks()
{
ProcessTracksScheduler.StartOnce(serviceProvider);
return Ok("Job scheduled");
}
和StartOnce方法,基本和Start一样:
public static void StartOnce(IServiceProvider provider)
{
try
{
ISchedulerFactory schedFact = new StdSchedulerFactory();
IScheduler sched = schedFact.GetScheduler();
sched.Start();
IJobDetail job = JobBuilder.Create<ProcessTracksJob>()
.WithIdentity("ProcessTracksOnce", "Group1")
.Build();
job.JobDataMap["tracksService"] = provider.GetService(typeof(ITracksService));
job.JobDataMap["cloudService"] = provider.GetService(typeof(ICloudService));
job.JobDataMap["broadcastService"] = provider.GetService(typeof(IBroadcastService));
job.JobDataMap["categoriesService"] = provider.GetService(typeof(ICategoriesService));
ITrigger trigger = TriggerBuilder.Create()
.StartNow()
.Build();
sched.ScheduleJob(job, trigger);
}
catch (ArgumentException e)
{
// Log the error
}
}
但是当我的工作被执行时,var broadcasts = broadcastService.GetAll(); 行抛出一个异常,说我的 DbContext 已被释放..
DbContext 通过 DI 传递到使用 ASP.Net-Core 的控制器/服务:
// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(this.Configuration.GetConnectionString("MyConnString")));
services.AddTransient<IBroadcastService, BroadcastsService>();
// Add the others services.
}
我尝试了很多东西,但找不到任何解决此问题的方法。
【问题讨论】:
-
您的 Quartz 代码是否在在您的 ASP.NET 应用程序中运行?如果是这样,你不应该这样做。 ASP.NET 用于短时间运行的任务,然后就结束了。通过在其中扩展它(例如运行 Quartz),您违背了 ASP.NET 的原则。只要它的生命周期结束,它就会终止。相反,您的应用程序应该与包含您的 Quartz 代码的专用进程通信。
-
我的 Quartz 代码在另一个项目中,而不是在我的 ASP.NET 应用程序中。你是这个意思吗?
-
该项目是否正在创建可执行文件?
-
不,你是对的。石英作业在 ASP.NET 应用程序中执行。不过暂时不成问题,工作一点也不繁重。
-
不管它有多重,您都无法控制 ASP.NET 和 IIS 何时回收应用程序池,或者任何数量的可能性。任何运行超过几秒钟的东西都有可能被终止。所以你可以想象,试图安排某事在未来运行一整天是行不通的。
标签: c# asp.net-core