.Net 6.0 Üzerinde Hangfire İmplementasyonu

Selamlar,

Bu makalede Hangfire’ı derinlemesine incelemek yerine, .Net 6.0 ile olan entegrasyonuna ve ilk başlayanlar için karşılaşılan sorunlara karşı, hap niteliğinde çözümlere yer verilecektir.

Şimdi gelelim Hangfire ne işe yarar sorusuna ?

Hangfire, arkada asenkron olarak çalışan, yani kullanıcıyı bekletmeyen (Background job) olarak tanımladığımız işler için kullanılan bir tooldur. Mutlaka bir depolama alanına, yani DB’ye ihtiyaç duyar. Depolama alanı olarak, birçok veritabanını destekler (SQL Server, MSMQ, Redis) gibi. Genellikle Time Schedule şeklinde tekrarlayan belli zaman aralıkları ile çalışan işlerde kullanılsalar da, birçok farklı kullanım şekilleri vardır.

Hangfire Çalışma Şekilleri:

  1. Fire & Forget: Bir kez çalışır ve biter. Hiç kullanma ihtiyacı duymadım :)
  2. Delayed: Yukarıdaki çalışma şekline benzeyen bir job çeşididir. Tek farkı, belirli bir sürenin sonunda, tek seferlik çalışan bir jobdır.
  3. Recurring: Tekrarlı olarak belirli bir zaman aralığında çalışacak olan bir job çeşididir. Bu makalenin esas değineceği job, budur.
  4. Continuations: Bir başka job’ın (scheduled) başarılı şekilde çalışmasından sonra, çalışacak olan job çeşididir.

Hangfire IIS üzerinde çalışan, bir JOB Schedule Tool’u dur.

Aslında IIS üzerinde belli zaman aralıkları ile çalışan yapılar, Cloud ile daha çok hayatımıza girmiştir. Çünkü, eskiden bu tarz işler için örneğin Windows ortamı için, Windows Servisler, daha sonra örneğin Azure ile cross platform çalışan, Worker Serviceler hayatımıza girdmiştir. Ama bu tarz servisler için, sanal bir sunucunun ayağı kaldırılması gerekmektedir. Bu da extra bir maliyete yol açtığı için, IIS üzerinde çalışan Quartz.NET, Hangfire gibi toolara ihtiya. duyulmuştur. Mesela Azure Cloud üzerinde de bunun karşılığı, “WebJobs” lardır. Makalesine buradan erişebilirsiniz.

Öncelikle, aşağıdaki gibi sıfırdan bir “HangfireTest” adında ASP .NET CORE Web API projesi yaratılır.

Hangfire’ın kullanılacağı .Net 6.0 projesine, aşağıdaki kütüphaneler eklenir.

Proje yaratıldığında otomatik gelen WeatherReport.cs sayfası, aşağıdaki gibi modifiye edilir:

“ReportWeather()” ve “ReportWeather2()” belli bir zaman aralığı ile Hangfire tarafından çalıştırılacak olan Dummy methodlardır. Belli zaman aralıkları ile, random olarak üretilen hava durumu sonuçları console’a yazmaktadırlar.

WeatherReport.cs:

Console basılan WeatherForecast modeli, aşağıdaki gibidir.

WeatherForecast.cs:

Şimdi sıra geldi, ilgili methodların çalışma zamanlarının belirlenmesine:

RecurringJobs.cs: Aşağıda görüldüğü gibi, yukarıda tanımlanan “ReportWeather” ve “ReportWeather2” methodları, belirli zaman aralıkları ile çalıştırılmak için Hangfire’ın => RecurringJob Sınıfına eklenmektedir.

1-) Hangfire Genel Sorunlardan 1.nin Çözümü:

Sorun, çalışması belli bir zaman aralığında tekrar edilecek methodların, Hangfire’a birden fazla eklenmesi. Kısaca, aynı methodun Hangfire’da çoklaması.

Çözüm => “RecurringJob.RemoveIfExists(nameof(weather.ReportWeather))“: İlgili methodun ismi “nameof()” şeklinde alınıp “RemoveIfExists()” methodu ile, aynısı var ise kaldırılır.

  • “RecurringJob.AddOrUpdate<IWeatherReport>(nameof(weather.ReportWeather), x =>” İlgili method interface’i ile “AddorUpdate()” methodu ile “RecurringJob” sınıfına “nameof()” methodu ile eklenir. Böylece daha sonra ilgili methodun zaten olup olmadığı, varsa kaldırılması gene bu “nameof()” methodu ile kontrol edilebilmektedir.
  • Ayralanacak zamanlama için birçok farklı yöntem kullanılabilir. İlk örnekde “Cron.Daily(16, 15)” şeklinde hergün saat 16:15 çalışmak üzere => “ReportWeather()” methodu tanımlanmıştır.
  • 2. örnekde “ReportWeather2()” methodu, “Cron.MinuteInterval(2)” tanımlaması ile her 2 dakkada bir çalışacak şekilde ayarlanmıştır.

2-) Hangfire Genel Sorunlardan 2.nin Çözümü:

Sorun Hangfire’da tanımlanan zamanın, gerçek zamandan 2 saat sonra gerçekleşmesi. Yani tanımlanan zamanın, Türkiye saatine uymaması.

Çözüm => “TimeZoneInfo.FindSystemTimeZoneById(“Turkey Standard Time”))” : Hangfire için çalışma zamanı, tanımlanan methodun TimeZone’ı, Türkiye için ayrıca tanımlanmalıdır.

Peki çok daha spesifik bir zaman aralığında, istenen methodun çalışması gerekir ise ? Size, şiddetle “https://crontab.guru” sitesini öneririm.

Örneğin : “RecurringJob.AddOrUpdate(() => weather.ReportWeather(), “5 4 * * sun”)” tanımlaması ile her pazar saat “4:05″‘de, ilgili methodun çalışması sağlanabilir. Bu tanımlamaya, “Cron” tanımlaması diyoruz. Ben bunu biraz, Regex’e benzetiyorum :)

Sıra geldi “Program.cs”‘de gerekli tanımların yapılarak, Hangfire’ın ayağa kaldırılmasına:

1-) Yazının başında bahsedildiği gibi, Hangfire bir DB’ye ihtiyaç duymaktadır. Benim tavsiyem, Hangfire’ı var olan projenin DB’sinde değil de, kendine özel ayrı bir DB’de çalıştırmanızdır. Aşağıda, local’de “Hangfire” adında yeni bir DB yaratılacak şekilde DB Connection,  tanımlanmıştır. Ayrıca HangfireServer, servislere eklenmiştir.

Hangfire ile beraber otomatik oluşan MsSqlDB aşağıdaki gibidir.

Not: Bazen yetkiden dolayı, ilgili DB otomatik oluşmaya biliyor. Bu durumda, manuel olarak “Hangfire” adında ya da yukarıdaki config’de “initial catalog”‘da ne tanımlanır ise, o isimde bir DB yaratmanız gerekmektedir. Uygulama ayağı kaldırılınca Hangfire’a ait ilgili tablolar, otomatik oluşacaktır.

2-) İstenir ise Hangfire, browser üzerinden yönetilir ve monitor edilebilir. Aşağıda Hangfire ekranına erişim için gerekli routing ve güvenlik için “username”, “password” tanımlanmaktadır. Username ve Password config dosyasından alınmaktadır. Tanımlanan routing sayesinde, “https://localhost:7290/job” yazılarak Hangfire sayfasına erişilebilir.

appsettings.json:

İstenir ise, RecurringJob’a eklenmiş olan methodlar zamanından önce de, manuel ekran üzerinden trigger edilebilir.

3-) Hangfire Genel Sorunlardan 3.nün Çözümü:

Hangfire servisinin, otomatik olarak ayağı kaldırılması, yani zamanlıyıcılı background işlerin kurulması, nasıl olmaktadır ? Detayalı cevap, hemen aşağıdaki 3. Maddede mevcuttur.

3-) Bu örnekde, Hangfire için tanımlanan methodlar, RecurringJobs class’ında “GetHourlyWeatherReport()” methodu altında tanımlanmıştır. İlgili sınıfa ait tüm methodların belirli bir perioda göre ayağ kaldırılması, aşağıdaki gibi “RecurringJobs.GetHourlyWeatherReport(_coreService)” şeklinde çağrılması ile otomatik olarak gerçekleşmektedir.

  • “new AutomaticRetryAttribute { Attempts = 3 }” : Tanımlaması ile, ilgili method başarılı şekilde çalıştırılamaz ise, hata alınılmayıncaya kadar 3 defa tekrar edilmektedir.

Program.cs:

*4-) Hangfire Genel Sorunlardan 4.nün Çözümü:

Peki bu çağrılan Hangfire methodlara, harici bir servis Inject’de etmek ister isek, bunu nasıl gerçekleştirebiliriz ?

Öncelikle gelin, solution’a “Service” adında yeni bir folder açıp “ICoreService“‘i aşağıdaki gibi oluşturalım.

Not: Gerçek bir projede, service katmanını ayrı bir Proje olarak yaratmanızda fayda var. Böylece, Solution’ın her yerinden ilgili servise erişebilirsiniz.

Service/ICoreService: 

Service/CoreService: Amaç, girilen sayısal sıcaklık değerinin yukarıda da görüldüğü gibi yazı ile de, ekrana basılmasını sağlamaktır. Yani kısaca örnek amaçlı bu servisde, rakkam => yazıya dönüştürülmektedir.

Peki şimdi bu servisi, Hangfire methodlarına nasıl Inject edeceğiz ?

1-) Program.cs: Öncelikle program.cs’e gelip ilgili “ICoreService”‘i ayağa kaldıralım. İlgili servisi başka yerde de kullanılabilsin diye, “Transient” olarak ayağı kaldırılır.

Ayrıca program.cs altında aşağıdaki gibi serviceProvider oluşturlup, coreService bu provider ile ayağı kaldırılır. Son olarak da, “GetHourlyWeatherReport(_coreService)” constractor’ına parametre olarak verilir.

2-) RecurringJobs.cs: Constructor’da “ICoreService“‘i, parametre olarak beklemektedir. Böylece aşağıda görüldüğü çalışma zamanı belirlenecek ve “WeatherReport” sınıfına ait methodlar’a erişilirken, ICoreService’in kullanılması için => WeatherReport sınıfının constructor’ına, ilgili servis parametre olarak geçilecektir.

3-) WeatherReport.cs: Aşağıda görüldüğü gibi  “public WeatherReport(ICoreService service) { _service = service; }” constructor’ında, “ICoreSerices”‘i almıştır.

  • _service.ConvertNumberToText(item.TemperatureC, out string text)“: Sayısal olarak gelen “TemperatureC” => yazıya ilgili servis sayesinde çevrilmiştir.
  • Debug.Write(text + ” | “)“: Sıcaklığın yazı ile olan karşılığı, yeni bir kolon olarak console’a yazdırılmıştır.

Böylece, “ICoreservice” => “WeatherReport” içinde, aşağıdaki adımlardan geçerek kullanılabilmiştir.

Program.cs (ICoreService ayağı kaldırıldı) => GetHourlyWeatherReport(Constructor) => WeatherReport(Usage)

5-) Hangfire Genel Sorunlardan 5 .nin Çözümü:

Hangfire’ın zaman zaman durması, ya da IIS üzerinde hiçbir işlem olmadığı noktada, sleep’e düşmesi.

1-) IIS Üzerinde  => Application Pools => .Net Core Project => Advanced Settings sekmesinden aşağıdaki ayarlar yapılır:

  • Start Mode:AlwaysRunning
  • Idle Time-out: 0

2-)  IIS =>Sites altında Advanced Settings => “Preload Enable : True” şeklinde atanır.

Geldik bir makalenin daha sonuna. Bu makalede Hangfire’a hangi durumlarda ihtiyacımız olabileceğine, .Net 6.0 bir WebApi projesine nasıl entegre edilebileceğine ve karşılaşılabilecek bir takım temel sorunların üstesinden, nasıl gelinebileceğine değindik.

Yeni bir makalede görüşmek üzere hepinize hoşçakalın.

Source Code: https://github.com/borakasmer/HangfireNet6

Kaynaklar:

 

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

10 Cevaplar

  1. Muhammed AKIN dedi ki:

    Bundan 3 ay önce implemente ettim hangfire’ı malesef elimde böyle bir kaynak yoktu ve bahsettiğiniz sorunların hepsini yaşadım neredeyse. İhtiyacı olanlar için mükemmel bir kaynak olmuş elinize emeğinize sağlık hocam

  2. Faruk dedi ki:

    Bu yazınızın faydalı olduğuna o kadar çok eminim ki ama yazılıma başlayalı henüz 1 hafta oldu :)
    Terimlere aşina olmak adına makaleler okumaya başladım ve bir hocam bize bu makalenizi paylaştı.
    Eğitim sürecim boyunca makalelerinizin tamamını okumaya karar verdim. Sizin gibi başarılı bir developer olmayı çok istiyorum.
    Rabbim size ve ailenize sağlıklı, huzurlu bir ömür versin. Kimseye muhtaç etmesin.

    • borsoft dedi ki:

      Teşekkürler Faruk,

      Zaten önce konuyu anlamak için terimlere aşina olmak yani neden bahsettiğimizi bilmek lazım.
      Bu yüzden de konuyu anlamasak dahi, sadece içinde geçen terimleri bile anlamak, yeni başlayan arkadaşlara büyük katkı sağlayacaktır.

      Görüşmek üzere..

  3. Serkan İnce dedi ki:

    Eline sağlık bu güzel yazı için. “Hangfire IIS üzerinde çalışan, bir JOB Schedule Tool’u dur” ifadesi yanıltıcı olabilir. Sanki windows ortamı şart gibi bir algı oluşabilir.

  4. çift klik dedi ki:

    İşleri her ne kadar da sıraya alsa da worker count ı sınırlamanız gerekebilir. birden fazla sitede host ediliyorsa görevi başka hostlara paylaştırıyor. localiniz de canlı sql bağlı ise görev sizin bilgisayarınıza da gelebilir. ayrıca hangfire, her verilen görevi işlemek zorunda da değil (bazı görevleri es geçebiliyor, görevi kesin yapacak diye bir şart yok, çok önemli bir görev tanımladıysanız görevin olup olmadığını ayrıca kontrol edin.)

  5. Berkay dedi ki:

    IIS üzerinden projeyi yayınlarken , App Pool üzerinde Recycling ayarı var , Fixed Intervals 1740 minutes olarak ayarlı olabiliyor , o ayarı kapatmamız lazım yoksa üç günde 1 Hangfire sunucusu düşüyor.

  6. murat dedi ki:

    bora hocam hangfire projesi ayrı normal backend projesi ayrı olacak sekılde bir yapı oldugunda backend business işlemlerinde hangfire jobs görev olusturmak için backend projesine de hangfire sunucu ayarları yapmak zorundamıyız yoksa client olarak jobs aktarımı yapabilir miyiz

    • borsoft dedi ki:

      Selamlar,
      Hayır ayrı bir ayar yapmanıza gerek yok ama,Hangfire’ın çalıştıracağı backend projesini, Hangfire projesine referans olarak vermek zorundasın..

      İyi çalışmalar.

  7. onur dedi ki:

    Merhaba BOra hocam. .net 6 da CronJobService kullanıyorum. çok fazla job var. monitör tool arıyorum? var mı bildiğiniz?

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.