21 Ocak 2021 Perşembe

SpringScheduling Kullanımı

Giriş
1. 1. @EnableScheduling anotasyonu koda eklenir.
2. Bean sınıfının bir metodu @Scheduled anotasyonu ile işaretlenir. Ancak bu genellikle yeterli olmaz. 

Çünkü 
2.1. SpringScheduling thread pool büyüklüğü 1 tek thread ile sınırlandırılmıştır. Yani thread pool büyüklüğü yetersizdir. Bu thread'in ismi "scheduling-1" dir.

Bu yüzden SchedulingConfigurer ile yeni bir thread pool yaratılır. Açıklaması şöyle
By default, Spring @Scheduled annotation uses default thread pool of size 1 ...
Bu ayarı yapınca yeni thread'lerin ismi "pool-X-thread-Y" haline gelir.

2.2. Thread pool büyüklüğü artırılsa bile aynı @Scheduled metodları sırayla çalıştırılır. Bu yüzden @Scheduled metodlarını @Async ile işaretlemek gerekebilir. Açıklaması şöyle
executions of scheduled method happen synchronously in respect to other executions of method.
Örnek
Şöyle yaparız
@Component
public class ScheduledService {

  @Scheduled(fixedDelay = 1000)
  @Async
  public void run1(){
    ...
  }
}
2.3 Aynı bean iki defa yüklenirse kod iki defa tetiklenebilir. Açıklaması şöyle. Bean'in bir defa yüklenmiş olmasına dikkat edilmeli.
Make sure that you are not initializing multiple instances of the same @Scheduled annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use @Configurable on bean classes which are annotated with @Scheduled and registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the @Configurable aspect, with the consequence of each @Scheduled method being invoked twice.
Bean Olarak ScheduledTask Tanımlama 
Sınıf @Component veya @Service olarak işaretli olmalıdır. Şöyle yaparız.
@Component 
public class ScheduledTask {

  @Scheduled(fixedRate = 60*1000)
  public void run() {
    ...
  }
}
XML Olarak ScheduledTask Tanımlama
Örnek - Dakika
XML ile tanımlamak için şöyle yaparız. Burada bean ve metod ismini belirtiriz.
<task:scheduled-tasks>
  <task:scheduled ref="offerScheduler" method="processOffer" cron="0 1 * * * *" />
</task:scheduled-tasks>
Bean'i tanımlamak için şöyle yaparız.
@Component
public class OfferScheduler {

  public void processOffer(){
    ...
  }
}
Örnek - Saat
Şöyle yaparız. Her gün sabah saat 3'te.
<task:scheduled ref="jobService" method="jobToRun" cron="0 0 3 * * *" />
Örnek
Şöyle yaparız.
<task:scheduled-tasks scheduler="myScheduler">
  <task:scheduled ref="restBean" method="addPhoto" fixed-delay="5000"/>
</task:scheduled-tasks>

<task:scheduler id="myScheduler"/>
Dağıtık Ortamda Scheduling
3 tane çözüm var. Açıklaması şöyle
1. You can configure your application to have multiple profiles. For example, use another profile ‘cron’. And start your application on only one server with this profile. So for example, in a production environment, you have three servers (S1, S2, S3), then you could run on S1 with profile prod and cron(-Dspring.profiles.active=prod,cron). And on S2 and S3 just use prod profile(-Dspring.profiles.active=prod). And in code, you can use @Profile("cron") scheduler classes. This way it will be executed only when the cron profile is active.

2. Use a distributed lock. If you have Zookeeper in your environment, you can use this to achieve a distributed locking system.

3. You can use some database(mysql) and create a sample code to get a lock on one of the tables and add an entry. And whichever instance gets the lock, will make an entry in this database and will execute the cron job. You need to put a check in your code if getLock() is successful. only then proceed with execution. Mysql has utilities like LOCK TABLES, which you could use to get away with concurrent read/writes.
ShedLock kütüphanesi, distributed lock için veri tabanını kullanıyor. Yani 3. çözüm

ShedLock Kullanımı
Shedlock yazısına taşıdım



Hiç yorum yok:

Yorum Gönder