Hangfire ile Zamanlanmış Görevler Çalıştırma
Geri planda(background) bazı işleri yapmak, yazılım geliştirme sürecinde sık karşılaştığımız bir durum. Örneğin, iş sürecini tıkamadan geri planda e-posta gönderimi veya uzun süren bir işi kullanıcıyı bekletmeden geri planda yapmak. Bunların dışında gece veya sistem rahatken çalışacak ve toplu yapılacak işleri de örnek olarak verebiliriz.
Geri planda uygulama çalıştırmanın farklı yöntemleri var. Uçtan uca geliştirilen Windows servisleri veya Unix ortamındaki daemon uygulamaları geliştirip bunları zamanlanmış görev olarak çalıştırabiliriz.
Bunların dışında yazılımcı olarak işimizi kolaylaştıran bazı hazır kütüphaneleri de kullanabiliriz. Örneğin .Net platformunda Quartz.net ve Hangfire adında yaygın şekilde kullanılan iki kütüphane bulunuyor. Bu yazımızda, Hangfire üzerine biraz konuşacağız.
Hangfire, bu konuda kullandığım en kapsamlı ve özellik bakımından yetenekli bir ürün diyebilirim. Projenizde kullanmak için öncelikle NuGet üzerinden HangFire paketini projemize ekliyoruz.
Yapacağımız işe göre Hangfire’ın kullanım şekli değişiyor. İşleri sınıflandırmak gerekirse sadece bir defa çalışacak işler ve sürekli tekrar edecek işler şeklinde ikiye ayırabiliriz.
Sadece bir kere çalışacak işler
“Fire and forget” olarak bilinen yöntemle bir kereliğine geri planda yapılmasını istediğimiz işlerdir.
var jobId = BackgroundJob.Enqueue(
() => Console.WriteLine("Fire-and-forget!"));
Bu işlere isterseniz belli bir zaman sonra yapmasını da söyleyebiliyorsunuz.
var jobId = BackgroundJob.Schedule(
() => Console.WriteLine("Delayed!"),
TimeSpan.FromDays(7));
Tekrarlayan İşler
Cron olarak tanımlanan zamanlanmış işlerinizi yönetmenizi sağlar. Cron tanımı için bu adresi inceleyebilirsiniz. Örneğin aşağıda günde 1 defa çalışacak bir iş parçası tanımı bulunmakta.
RecurringJob.AddOrUpdate(
() => Console.WriteLine("Recurring!"),
Cron.Daily);
Hangfire’a bir iş eklendiğinde o işe ait bir id bilgisi geri döner. Bu bilgiyi isterseniz ilişkili işleriniz varsa kullanabilirsiniz. Örneğin, bu görev bittikten sonra şu görevi başlat gibi. Aşağıdaki örnek kod parçasında bu kullanım şeklini görebilirsiniz.
BackgroundJob.ContinueWith(
jobId,
() => Console.WriteLine("Continuation!"));
Hangfire ücretsiz bir kütüphane olmakla birlikte kurumsal uygulamalarda ihtiyaç duyulan bazı özellikleri barındıran ücretli bir versiyonu da bulunmaktadır. Örneğin Batch olarak birden fazla görevi grup olarak gerçekleştirmek isterseniz, bu özelliği ücretli sürümünde kullanabilirsiniz.
Hangfire’ın bir diğer özelliği kullandığınız diğer sistemlerle entegre çalışabilmesidir. Birçok veritabanı, kuyruk yapısı ve depolama sistemleriyle entegre olmanızı sağlayan yardımcı yapıları bulundurmaktadır. Örneğin aşağıda görev bilgilerini tutmak için kullanabileceğiniz sistemleri görebilirsiniz.
Aşağıda Hangfire için oluşan örnek bir tablo kümesini görebilirsiniz.
Kullandığınız IoC sistemleriyle entegre olması için yine Hangfire’ın birçok IoC yardımcı paketi bulunmakta. Autofac, Ninject, StructureMap, Unity, Windsor bunlardan birkaçı.
Hangfire’ın kullanım şekillerine ve yardımcı yapılarına baktıktan sonra projemizde Hangfire’ı nasıl yapılandıracağımıza ve çalışan görevleri nasıl izleyeceğimize bakalım.
Hangfire’ı uygulamamızda kullanabilmek için önelikle proje başlangıcındaki uygun bir metotta yapılandırmasını yapmamız gerekiyor. Aşağıdaki Configuration metodunda yazılan yapılandırmalarını görebilirsiniz. Burada dikkat çekmek istediğim nokta en altta bulunan UseHangfireServer metodu. UseHangfireServer’ı debug esnasında çalıştırırsak lokal makinamız da Hangfire server gibi davranacaktır. Job’ları debug etme ihtiyacımız olmadığında bu metodun sadece test veya production ortamında çalıştırılması daha doğru olacaktır.
Son olarak çalıştırdığımız görevleri nereden nasıl izleyebileceğimize bakalım. Hangfire görevlerini takip edeceğimiz bir dashboard’a sahip. Dashboard’a erişmek için ana site adresinin sonuna “/hangfire” yazmak yeterli olacaktır.
İşin son durumu, başarılı çalışmış mı, paket içeriği vs bilgileri burada görebiliyorsunuz. Dashboard’a sadece lokalden erişim bulunmaktadır. Belli rollere göre uzaktan erişimi aktif etmek için IDashboardAuthorizationFilter özelliğini kullanarak kendi yetkilendirmenizi oluşturabilirsiniz. Örnek kullanım için tıklayınız.
NOT: Hangfire başarılı sonuçlanmayan işleri vereceğiniz konfigürasyona göre tekrar çalıştırmaya dener. Varsayılan davranış 10 kereye kadar başarısız olması durumunda tekrar deneme şeklindedir.
Son olarak Hangfire kullanımıyla ilgili dikkat edilmesi gereken bir kaç önemli noktayı aktarayım:
- Asp.net uygulamanız içerisinde konumlandırdığınız Hangfire işlerinizde session vs gibi web nesnelerine erişemezsiniz. Session nesnenizi web için ayrı, Hangfire için ayrı inject ederseniz daha rahat kullanabilirsiniz.
- Job’larınıza parametre geçerken büyük nesneler vermek yerine (entity vs) primitive bilgi gönderip job içinde büyük nesneyi almak daha kullanışlı olacaktır. Hangfire, parametreyi json serialize/deserialize edeceği için büyük nesne gönderilmesi dezavantaj olacaktır.
- Job işlenirken yarıda kalmış olabilir, bu durumda job tekrar çalıştırılacaktır. Bu gibi durumlarla karşılaşabileceğinizi düşünerek önlem almak (veritabanı işlemleri için transaction kullanımı) gerekmektedir.
- Web uygulamanızdan Hangfire’ı ayırmak isterseniz Hangfire’ı Console veya Windows Service olarak da kullanabilirsiniz.