Планировщик на ASP.NET 6 с помощью Quartz.NET и мониторинга SignalR

  • Михаил
  • 8 мин. на прочтение
  • 26
  • 23 Feb 2024
  • 23 Feb 2024

В этой статье мы собираемся использовать Quartz.NET для планирования наших заданий и использовать Signalr для просмотра мониторинга результатов/прогресса. 

Создайте js-файл SignalR.

создайте файл hub.js и сохраните его в папке wwwroot->js.

const connection = new signalR.HubConnectionBuilder().withUrl("/hub").build();
async function start() {
try {
await connection.start();
console.log("SignalR Connected.");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
connection.onclose(async () => {
await start();
});
start();
connection.on("ConcurrentJobs", function (message) {
var li = document.createElement("li");
document.getElementById("concurrentJobs").appendChild(li);
li.textContent = `${message}`;
});
connection.on("NonConcurrentJobs", function (message) {
var li = document.createElement("li");
document.getElementById("nonConcurrentJobs").appendChild(li);
li.textContent = `${message}`;
});

HTML для отображения сообщения

В Index.cshtml добавьте приведенный ниже код для отображения сообщения от SignalR.

<div class="container">
<div class="row">
<div class="col-6">
<ul id="concurrentJobs"></ul>
</div>
<div class="col-6">
<ul id="nonConcurrentJobs"></ul>
</div>
</div>
</div>
<script src="~/microsoft/Signalr/dist/browser/signalr.js"></script>
<script src=~/js/hub.js></script>

Центр вакансий

Создайте имя файла класса CS JobsHub и замените приведенным ниже кодом.

public class JobsHub : Hub
{
//message used for concurrent job message
public Task SendConcurrentJobsMessage(string message)
{
return Clients.All.SendAsync("ConcurrentJobs", message);
}
​
//message used for nonconcurrent job message
public Task SendNonConcurrentJobsMessage(string message)
{
return Clients.All.SendAsync("NonConcurrentJobs", message);
}​
}

Создавайте рабочие места

  • Параллельная работа

Создайте файл класса cs с именем ConconcurrentJob и замените приведенным ниже кодом.

public class ConconcurrentJob : IJob
{
private static int _counter = 0;
private readonly IHubContext<JobsHub> _hubContext;
​
public ConconcurrentJob(IHubContext<JobsHub> hubContext)
{
_hubContext = hubContext;
}
​
public async Task Execute(IJobExecutionContext context)
{
var count = _counter++;
​
//start the job
var beginMessage = $"Conconcurrent Job BEGIN {count} {DateTime.UtcNow}";
await _hubContext.Clients.All.SendAsync("ConcurrentJobs", beginMessage);
​
//we have long running job
Thread.Sleep(5000);
​
//complete the job
var endMessage = $"Conconcurrent Job END {count} {DateTime.UtcNow}";
await _hubContext.Clients.All.SendAsync("ConcurrentJobs", endMessage);
}
}

Создайте файл класса cs с именем NonConconcurrentJob и замените приведенным ниже кодом.

public class ConconcurrentJob : IJob
{
private static int _counter = 0;
private readonly IHubContext<JobsHub> _hubContext;
​
public ConconcurrentJob(IHubContext<JobsHub> hubContext)
{
_hubContext = hubContext;
}
​
public async Task Execute(IJobExecutionContext context)
{
var count = _counter++;
​
//start the job
var beginMessage = $"Conconcurrent Job BEGIN {count} {DateTime.UtcNow}";
await _hubContext.Clients.All.SendAsync("nonConcurrentJobs", beginMessage);
​
//we have long running job
Thread.Sleep(5000);
​
//complete the job
var endMessage = $"Conconcurrent Job END {count} {DateTime.UtcNow}";
await _hubContext.Clients.All.SendAsync("nonConcurrentJobs", endMessage);
}
}

Program.cs

Добавьте приведенный ниже код в Program.cs

builder.Services.AddQuartz(q =>
{
q.UseMicrosoftDependencyInjectionJobFactory();
​
var conconcurrentJobKey = new JobKey("ConconcurrentJob");
q.AddJob<ConconcurrentJob>(opts => opts.WithIdentity(conconcurrentJobKey));
q.AddTrigger(opts => opts
.ForJob(conconcurrentJobKey)
.WithIdentity("ConconcurrentJob-trigger")
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(5)
.RepeatForever()));
​
var nonConconcurrentJobKey = new JobKey("NonConconcurrentJob");
q.AddJob<NonConconcurrentJob>(opts => opts.WithIdentity(nonConconcurrentJobKey));
q.AddTrigger(opts => opts
.ForJob(nonConconcurrentJobKey)
.WithIdentity("NonConconcurrentJob-trigger")
.WithSimpleSchedule(x => x
.WithIntervalInSeconds(5)
.RepeatForever()));
​
});
​
builder.Services.AddQuartzHostedService(
q => q.WaitForJobsToComplete = true);
​
builder.Services.AddSignalR();


app.UseEndpoints(endpoints =>
{
endpoints.MapHub<JobsHub>("/hub");
});