VS2022需等Quartz后台任务完成才启动Swagger浏览器问题求助
问题
我正在开发一个暴露API并使用Quartz运行后台任务的简单应用,该应用需重复执行抓取任务与检查任务。从VS2022启动应用时,Chrome要等到检查任务完成第一次迭代才会打开Swagger页面。这虽不影响核心功能但较为烦人,我可以手动打开Swagger。相关代码如下:
任务定义
public sealed class CachingBackgroundJob : IJob { private readonly ISchedulerService _schedulerService; public CachingBackgroundJob(ISchedulerService schedulerService) { _schedulerService = schedulerService; } public async Task Execute(IJobExecutionContext context) { await _schedulerService.FillCache(context.CancellationToken); } }
public sealed class SchedulingBackgroundJob : IJob { private readonly ISchedulerService _schedulerService; public SchedulingBackgroundJob(ISchedulerService schedulerService) { _schedulerService = schedulerService; } public async Task Execute(IJobExecutionContext context) { await _schedulerService.CheckHealth(context.CancellationToken); } }
依赖注入配置
public static class DependencyInjection { public static void AddScheduler(this IServiceCollection services) { services.AddQuartz(opts => { var cachingBackgroundJobKey = JobKey.Create(nameof(CachingBackgroundJob)); opts.AddJob<CachingBackgroundJob>(cachingBackgroundJobKey) .AddTrigger(trigger => { trigger.ForJob(cachingBackgroundJobKey) .WithSimpleSchedule(schedule => { schedule.WithRepeatCount(0); }); }); var matcher = KeyMatcher<JobKey>.KeyEquals(cachingBackgroundJobKey); opts.AddJobListener<CachingJobCompletionListener>(matcher); }); services.AddQuartzHostedService(); } }
任务监听器
internal class CachingJobCompletionListener : IJobListener { public string Name => "CachingBackgroundJobCompletedListener"; public Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default) { return Task.CompletedTask; } public Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default) { return Task.CompletedTask; } public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException? jobException, CancellationToken cancellationToken = default) { var scheduler = context.Scheduler; var schedulingBackgroundJobTrigger = TriggerBuilder.Create() .WithSimpleSchedule(schedule => { schedule.WithIntervalInMinutes(1); schedule.RepeatForever(); }) .StartNow() .Build(); var jobDetail = JobBuilder .Create() .OfType<SchedulingBackgroundJob>() .WithIdentity(JobKey.Create(nameof(SchedulingBackgroundJob))) .DisallowConcurrentExecution() .Build(); await scheduler.ScheduleJob(jobDetail, schedulingBackgroundJobTrigger, cancellationToken); } }
Program.cs
var builder = WebApplication.CreateBuilder(args); builder.Configuration.AddEnvironmentVariables(); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddRouting(options => options.LowercaseUrls = true); IConfiguration redisConfiguration = builder.Configuration.GetSection("Caching"); string connectionString = redisConfiguration["redis"]!; builder.Services.AddSingleton<IConnectionMultiplexer>((serviceProvider) => ConnectionMultiplexer.Connect(connectionString)); ThreadPool.SetMinThreads(100, 100); builder.Services.AddScoped<ISchedulerService, SchedulerService>(); builder.Services.AddHttpClient(); builder.Services.AddScheduler(); builder.Host.UseSerilog((context, config) => { config.ReadFrom.Configuration(context.Configuration); }); var applicationAssembly = AppDomain.CurrentDomain.Load("Example.Application"); builder.Services .AddMediatR(opts => opts.RegisterServicesFromAssembly(applicationAssembly)) .AddFluentValidationAutoValidation() .AddValidatorsFromAssembly(applicationAssembly); ValidatorOptions.Global.DefaultRuleLevelCascadeMode = CascadeMode.Stop; var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseSerilogRequestLogging(); app.UseAuthorization(); app.MapControllers(); app.Run();
请问是什么原因导致VS2022自动启动浏览器的操作被阻塞?
原因分析与解决方案
核心原因
AddQuartzHostedService()的默认配置会让ASP.NET Core主机在启动时,同步等待所有Quartz初始任务执行完成,才会继续完成Web应用的启动流程。你的CachingBackgroundJob被配置为启动后立即执行一次,主机要等它执行完毕才会触发VS自动打开浏览器的操作,因此出现了阻塞现象。
具体来说,QuartzHostedService的WaitForJobsToComplete属性默认值为true,这会强制主机等待所有任务完成后才完成启动。
解决方案
修改AddQuartzHostedService的配置,将WaitForJobsToComplete设置为false,让Quartz后台任务在应用启动后异步执行,不阻塞Web应用的启动:
public static class DependencyInjection { public static void AddScheduler(this IServiceCollection services) { services.AddQuartz(opts => { var cachingBackgroundJobKey = JobKey.Create(nameof(CachingBackgroundJob)); opts.AddJob<CachingBackgroundJob>(cachingBackgroundJobKey) .AddTrigger(trigger => { trigger.ForJob(cachingBackgroundJobKey) .WithSimpleSchedule(schedule => { schedule.WithRepeatCount(0); }); }); var matcher = KeyMatcher<JobKey>.KeyEquals(cachingBackgroundJobKey); opts.AddJobListener<CachingJobCompletionListener>(matcher); }); // 修改此处配置,禁用等待任务完成的逻辑 services.AddQuartzHostedService(options => { options.WaitForJobsToComplete = false; }); } }
这样修改后,Web应用启动流程不会被Quartz任务阻塞,VS会在应用启动完成后立即打开Swagger页面,而CachingBackgroundJob会在后台异步执行。
内容的提问来源于stack exchange,提问作者anon37894203
相关产品推荐
相关产品推荐

