Job scheduling, özellikle enterprise uygulamalarla daha fazla öne çıkan ve arka planda çalışacak işleri zaman planına göre başlatan ve monitor eden sistemlerdir. İşlerin çalıştırılması belirli periodlarda yapılabilieceği gibi; tatil gunleri, her ayın ilk iş günü, vs. gibi daha karmaşık tanımlamalar ile de gerçekleştirilebilir. Hâlihazırda RDBMS veya Unix gibi işletim sistemleri ile istenilen zamanlarda arka planda çalışacak işler yaratabilirsiniz. Fakat bu sistemler load-balancing, fail-over ve clustering gibi enterprise uygulamaların en çok ihtiyaç duyduğu fonksiyoneliteleri çoğunlukla karşılayamaz ve bu ihtiyacı karşılayacak kodu kendiniz yazmanız gerekecektir. Bu sebeple bahsi geçen ihtiyaçlara cevap verecek gerçek bir job scheduler kullanımına ihtiyaç duyarız.
Java ile uygulama geliştiriyorsanız güvenilir bir open source çözüm olan Quartz Scheduler ‘ı birçok sebeple tercih edebilirsiniz. Quartz, OpenSymphony açık kaynak topluluğu altında geliştirilen bir projedir. Yaptığı işlere göre oldukça küçük boyutlu bir API dir. Standart veya enterprise java uygulamalarında çok basit bir konfigurasyon ile kullanılabilir. J2EE container içinde kullanıldığında XA transactionlarına dahil olabilir.
Quartz ın en fazla öne çıkan özelliği clustered node lar üzerinden çalışabilmesidir. Aynı konfigurasyon birden fazla sistem üzerine deploy edilerek tüm node ların tek bir scheduler gibi çalışması sağlanır. Quartz, instance lar arasındaki senkronizasyonu standart JDBC api ile sağlar. Database de kurulan mantıksal kilitleme mekanizmasıyla bir işin farklı instance lar üzerinde aynı anda çalışması önlenir. Instance lar arasındaki senkronizasyonun bozulmaması için tüm instance lar aynı konfigurasyon dosyasına sahip olmalıdır. Quartz load-balancing yeteneğini yine JDBC api ile gerçekleştirir. Bir cluster içindeki tüm instance lar aynı quartz tablolarına bakarlar. Çalışma zamanı gelmiş bir job tek bir quartz instance ı tarafından çalıştırılır.
Enterprise sistemlerin her zaman online durumda olmasını bekleriz fakat beklenmedik sebeplerle sistemimiz kapanabilir veya hata alabilir. Bu durumda sistemin kaldığı noktadan işine devam etmesini beklemek en doğal hakkımız. Quartz, fail-over özelliği ve jdbc persistence ile bu işin hakkını veren bir kütüphanedir. Scheduler beklenmedik şekilde kapanır veya kapatılırsa, tekrar açıldığında kaldığı yerden devam edebilir.
Job – Trigger kavramları
Job lar birer java interface olup bunları implemente eden her şey quartz tarafından çalıştırılabilir. Fakat job lar scheduler a zaman planlarını söyleyemezler. Bir job scheduler a submit edilirken job ı çalıştıracak trigger ile beraber submit edilir. Bu şekilde job ın istenilen zaman planına göre trigger edilmesi sağlanır.
Joblar stateful veya stateless olmalarına göre iki farklı job interface ini implement ederler. Stateless joblar ardışık execution lar arasında state datası tutmazken, stateful joblar bu datayı bir sonraki executiona aktarırlar. Bir job çalışırken execution ın uzun sürmesi veya scheduler in bir sure kapalı kalması gibi sebeplerle çalışması gereken zamanını kaçırabilir (misfire). Böyle durumlarda stateless joblar eğer o an çalışıyorsa bile başka bir thread tarafından tekrar çalıştırılırlar. Stateful joblar tek bir state datası üzerinde çalıştıklarından herhangi bir anda sadece bir örneği çalışır.
SimpleTrigger belirli periyodlarda birbirini takip eden zaman aralıklarında çalışır. Sonsuz döngüde çalışabileceği gibi n defa çalışmak üzere programlanabilir. CronTrigger ise takvim tabanlı bir notasyon olan cron ifadesini kullanır. SimpleTrigger dan daha kullanışlıdır fakat tam olarak kapsamaz. SimpleTrigger ında kendine özgü güçlü özellikleri mevcuttur. Cron ifadesi ile çok karmaşık zamanlama planları yaratılabilir. Örneğin “0 30 10-13 ? * WED,FRI” ifadesi her Çarşamba ve Cuma saat 10 ila 13 arası yarım saatte bir çalışması gereken bir trigger ın zaman planını ifade eder. Cron ifadesi bu kadar esnek olmasına karşın her türlü zamanlama planı yaratmak mümkün olmaz. Bunun için custom trigger yazmanız gerekebilir. Bundan sonraki yazımlarımda custom bir trigger ın nasıl yazılacağından bahsedeceğim.
JobStore ile tanımların saklanması
Konfigurasyona göre job ve trigger tanımları memory (memory-store) de veya database (jdbc-store) ile persist edilir. Network gecikmeleri ve database erişimleri göz önüne alındığında memory-store un çok daha hızlı olduğunu söyleyebiliriz. Fakat load-balancing ve fail-over gibi gelişmiş özellikleri kullanacaksanız jdbc-store kullanmalısınız.
Job ve trigger tanımlarını memory-store da saklamak sizin için en ideal çözüm ise scheduler her restart ediliğinden job ve trigger tanımlarını yeniden yüklemek yazılımcının sorumluluğundadır. Çünkü scheduler kapandığıdan tüm tanımlarınız kaybolmuş olacaktır. Jdbc-store kullanıldığında ise job ve trigger tanımları quartz tablolarında tutulduğundan sistem kaldığı yerden çalışmasına devam edecektir. Jdbc-store kullanırken yaratılan connection sayısı thread sayısından her zaman fazla olmalıdır. Aksi halde JTA transaction larda deadlock problemleri yaşayabilirsiniz.
Custom bir cron trigger yazmak ve jdbc-store kullanmak isterseniz sınıflarınızı CronTrigger dan extend etmemeye dikkat edin. Trigger serialize edilirken trigger tipi instanceof ile kontrol edildiğinden custom trigger ınız hiçbir zaman serialized edilmeyecektir, standart CronTrigger gibi saklanacak ve CronTrigger gibi çalışacaktır. Ayrıca custom trigger larınızı org.quartz paketi içine yazmayı da unutmayın. Aksi halde farklı bir paket içinden sınıflarınız yüklenmeyecektir.
Spring ile Entegrasyon
Birçok açık kaynak yazılımın olduğu gibi quartz ı da spring ile beraber kullanabilirsiniz. Fakat spring entegrasyonunun çok esnek olduğu söylenemez. SchedulerFactoryBean instance ı AOP Proxy olarak yaratıldığından uygulama içinde object referece ına ulaşmak kolay değildir. Bunun yerine kendi yazacağınız bir singleton bean ile scheduler ı kontrol edebilirsiniz.

