Kako rasporediti poslove pomoću Quartz.NET-a u ASP.NET Core

Kada radite na web aplikacijama, često ćete trebati izvršavati određene zadatke u pozadini. U nekim će slučajevima to biti zadaci koje treba izvršiti u unaprijed definiranim intervalima.

Quartz.NET je .NET port otvorenog koda popularnog okvira za planiranje poslova Java. Dugo se koristi i pruža izvrsnu podršku za rad s Cron izrazima. Možete saznati više o Quartz.NET-u iz ranijeg posta ovdje. 

Ovaj članak predstavlja raspravu o tome kako možemo raditi s Quartz.NET-om u ASP.NET Core za planiranje pozadinskih poslova.

Da biste radili s primjerima koda iz ovog članka, u sustavu biste trebali instalirati Visual Studio 2019. Ako još nemate kopiju, ovdje možete preuzeti Visual Studio 2019. 

Stvorite projekt ASP.NET Core API

Prvo, kreirajmo ASP.NET Core projekt u Visual Studiju. Pod pretpostavkom da je Visual Studio 2019 instaliran u vašem sustavu, slijedite korake opisane u nastavku da biste u Visual Studiou stvorili novi ASP.NET Core projekt.

  1. Pokrenite Visual Studio IDE.
  2. Kliknite "Stvori novi projekt".
  3. U prozoru "Stvori novi projekt" s popisa predložaka odaberite "ASP.NET Core Web Application".
  4. Kliknite Dalje.
  5. U sljedećem prozoru "Konfiguriranje novog projekta" navedite naziv i mjesto za novi projekt.
  6. Kliknite Stvori.
  7. U prozoru "Stvori novu web-aplikaciju ASP.NET Core" odaberite .NET Core kao vrijeme izvođenja i ASP.NET Core 2.2 (ili noviju) s padajućeg popisa na vrhu. Ovdje ću koristiti ASP.NET Core 3.0.
  8. Odaberite "API" kao predložak projekta da biste stvorili novu aplikaciju ASP.NET Core API. 
  9. Obavezno označite potvrdne okvire "Omogući podršku za Docker" i "Konfiguriraj za HTTPS" jer ovdje nećemo koristiti te značajke.
  10. Provjerite je li provjera autentičnosti postavljena na "Bez provjere autentičnosti" jer ni mi nećemo koristiti provjeru autentičnosti.
  11. Kliknite Stvori. 

To će stvoriti novi ASP.NET Core API projekt u Visual Studiju. Odaberite mapu rješenja Controllers u prozoru Solution Explorer i kliknite "Dodaj -> Controller ..." da biste stvorili novi kontroler nazvan DefaultController.

Dalje, za rad s Quartzom trebali biste instalirati Quartz paket od NuGet-a. To možete učiniti putem upravitelja paketa NuGet unutar IDE-a Visual Studio 2019 ili izvršavanjem sljedeće naredbe na konzoli upravitelja paketa NuGet:

Instalirajte-paket kvarc

Quartz.NET poslovi, okidači i planeri 

Tri glavna koncepta u Quartz.NET-u su poslovi, okidači i planeri. Posao sadrži kôd za izvršavanje zadatka ili posao koji treba izvršiti. Posao predstavlja klasa koja implementira IJob sučelje. Okidač se koristi za određivanje rasporeda i ostalih detalja posla. Možete iskoristiti okidač da odredite kako treba izvršiti posao. Planer je komponenta koja je odgovorna za anketiranje i izvršavanje poslova na temelju unaprijed definiranih rasporeda.

Stvorite rokovnik pomoću Quartz.NET

Treba napomenuti da u aplikaciji možete imati više planera. Međutim, ovdje ćemo koristiti jednostavnost jednog planera radi jednostavnosti. Sljedeći isječak koda ilustrira kako možete stvoriti instancu planera.

var planer = StdSchedulerFactory.GetDefaultScheduler (). GetAwaiter (). GetResult ();

Jednom kada je planer kreiran, možete koristiti sljedeći kôd u metodi ConfigureServices datoteke Startup.cs da biste dodali instancu planera kao jednokratnu uslugu.

services.AddSingleton (rokovnik);

Pokrenite i zaustavite rokovnik pomoću Quartz.NET

Za pokretanje i zaustavljanje planera iskoristit ćemo uslugu hostinga. Da biste to učinili, morate stvoriti klasu koja implementira sučelje IHostingService kako je prikazano u isječku koda koji je dat u nastavku.

javna klasa CustomQuartzHostedService: IHostedService

{

        privatno samo za čitanje IScheduler _scheduler;

        javna CustomQuartzHostedService (planer ISchedulera)

        {

            _scheduler = rokovnik;

        }

        javni async zadatak StartAsync (CancellationToken cancellationToken)

        {

            await _scheduler? .Start (cancellationToken);

        }

        javni async zadatak StopAsync (CancellationToken cancellationToken)

        {

            await _scheduler? .Shutdown (cancellationToken);

        }

 }

Imajte na umu da biste trebali registrirati hostiranu uslugu u zbirci usluga u metodi ConfigureServices pomoću isječka koda navedenog u nastavku.

services.AddHostedService ();

Evo ažurirane metode ConfigureServices za vašu referencu:

javna praznina ConfigureServices (usluge IServiceCollection)

{

    services.AddControllers ();

    var planer =

    StdSchedulerFactory.GetDefaultScheduler (). GetAwaiter (). GetResult ();

    services.AddSingleton (rokovnik);

    services.AddHostedService ();

}

Napravite posao pomoću Quartz.NET-a

Kao što sam ranije rekao, posao je klasa koja implementira IJob sučelje i sadrži metodu Execute (). Metoda Execute () prihvaća instancu tipa IJobExecutionContext.

Sljedeći isječak koda ilustrira klasu posla koja sadrži i asinkronu metodu Execute (). Ova metoda sadrži kod koji odgovara zadatku koji bi vaš posao trebao obaviti.

[DisallowConcurrentExecution]

javni razred NotificationJob: IJob

    {

        privatno samo za čitanje ILogger _logger;

        javni NotificationJob (zapisivač ILogger)

        {

            _logger = zapisničar;

        }

        javno izvršavanje zadatka (kontekst IJobExecutionContext)

        {

            _logger.LogInformation ("Pozdrav svijetu!");

            return Task.CompletedTask;

        }

    }

Stvorite tvornicu poslova pomoću Quartz.NET-a

Tvornica poslova je klasa koja nasljeđuje sučelje IJobFactory i implementira metode NewJob () i ReturnJob (). Sljedeći isječak koda može se koristiti za stvaranje tvorničke klase koja može stvoriti i vratiti instancu posla.

javna klasa CustomQuartzJobFactory: IJobFactory

    {

        privatno samo za čitanje IServiceProvider _serviceProvider;

        javni CustomQuartzJobFactory (usluga ISroviceProviderProvider)

        {

            _serviceProvider = serviceProvider;

        }

        javni IJob NewJob (TriggerFiredBundle triggerFiredBundle,

        Planer ISchedulera)

        {

            var jobDetail = triggerFiredBundle.JobDetail;

            return (IJob) _serviceProvider.GetService (jobDetail.JobType);

        }

        public void ReturnJob (posao u IJob-u) {}

    }

Imajte na umu da ova implementacija ne koristi spajanje poslova. Ako želite koristiti spremanje poslova, trebali biste promijeniti metodu NewJob (), a zatim implementirati metodu ReturnJob ().

Stvorite klasu JobMetadata za pohranu metapodataka posla

Upotrijebit ćemo prilagođenu klasu za spremanje metapodataka povezanih s poslom, tj. ID-a posla, imena itd. Sljedeća klasa predstavlja klasu metapodataka posla.

javni razred JobMetadata

    {

        javni vodič za posao {get; postavljen; }

        javni tip JobType {get; }

        javni niz JobName {get; }

        javni niz CronExpression {get; }

        javni JobMetadata (Guid Id, Type jobType, string jobName,

        string cronExpression)

        {

            JobId = Id;

            JobType = tip posla;

            JobName = ime posla;

            CronExpression = cronExpression;

        }

    }

Stvorite hostiranu uslugu za pokretanje i zaustavljanje planera Quartz.NET

Dalje, trebat ćemo implementirati uslugu hostiranja. Hostirana usluga je klasa koja implementira sučelje IHostedService i pokreće kvarcni planer. Sljedeći popis kodova prikazuje prilagođenu hostiranu klasu usluge.

javna klasa CustomQuartzHostedService: IHostedService

    {

        privatno samo za čitanje ISchedulerFactory planerFactory;

        privatno samo za čitanje IJobFactory jobFactory;

        privatno samo za čitanje JobMetadata jobMetadata;

        javna CustomQuartzHostedService (ISchedulerFactory

            planerFactory,

            JobMetadata jobMetadata,

            IJobFactory posaoFactory)

        {

            this.schedulerFactory = planeraFactory;

            this.jobMetadata = jobMetadata;

            this.jobFactory = jobFactory;

        }

        javni IScheduler Planer {get; postavljen; }

        javni async zadatak StartAsync (CancellationToken cancellationToken)

        {

            Planer = čekati planerFactory.GetScheduler ();

            Planer.JobFactory = tvornica posla;

            var posao = CreateJob (jobMetadata);

            var okidač = CreateTrigger (jobMetadata);

            čekati Scheduler.ScheduleJob (posao, okidač, otkazivanjeToken);

            čekati Scheduler.Start (cancellationToken);

        }

        javni async zadatak StopAsync (CancellationToken cancellationToken)

        {

            čekati Planera?? Isključivanje (cancellationToken);

        }

        privatni ITrigger CreateTrigger (JobMetadata jobMetadata)

        {

            vrati TriggerBuilder.Create ()

            .WithIdentity (jobMetadata.JobId.ToString ())

            .WithCronSchedule (jobMetadata.CronExpression)

            .WithDescription ($ "{jobMetadata.JobName}")

            .Izgraditi();

        }

        privatni IJobDetail CreateJob (JobMetadata jobMetadata)

        {

            vratiti JobBuilder

            .Create (jobMetadata.JobType)

            .WithIdentity (jobMetadata.JobId.ToString ())

            .WithDescription ($ "{jobMetadata.JobName}")

            .Izgraditi();

        }

    }

Sljedeći isječak koda prikazuje cjeloviti kôd metode ConfigureServices klase Startup.

javna praznina ConfigureServices (usluge IServiceCollection)

{

services.AddControllers ();

usluge.AddSingleton ();

usluge.AddSingleton ();

usluge.AddSingleton ();

services.AddSingleton (novi JobMetadata (Guid.NewGuid (), typeof (NotificationJob), "Notification Job", "0/10 * * * *?"));

services.AddHostedService ();

}

I to je sve što trebate učiniti! Kada izvršite aplikaciju, primijetit ćete da se metoda Execute () klase NotificationJob izvodi jednom u 10 sekundi.

Quartz.NET je dobar izbor za implementaciju planera u vaše aplikacije. Možete iskoristiti značajku postojanosti u Quartz.NET-u za pohranu svojih poslova u bazu podataka kao što su SQL Server, PostgreSQL ili SQLite.