Ana içeriğe geç

1.8. Scheduling#

Zamanlanmış görevler tanımlanmasını sağlayan bileşendir. Uygulama cluster özelliklerini sağlar (distributable). Quartz library'si kulanılmaktadır.

Konfigurasyon#

Gradle Bağımlılıkları

implementation(
        [group: 'tr.com.havelsan.framework.scheduling', name: 'hvl-quartz']
)

Cluster Konfigürasyonları

Veritabanında cluster olan bir uygulamadır. Quartz tabloları manuel ya da liquibase ile initialize edilebilir.

spring:
  quartz:
    scheduler-name: ${spring.application.name}
    auto-startup: true
    startup-delay: 2s
    overwrite-existing-jobs: true
    job-store-type: jdbc
  liquibase:
    parameters:
      quartz-jdbc-job-store-schema: ${hvl.scheduling.quartz.jdbc-job-store.schema-name}
      quartz-jdbc-job-store-table-prefix: ${hvl.scheduling.quartz.jdbc-job-store.table-prefix}

Çevre Değişkenleri

Cloud profili olarak "hvl-scheduling" verilerek, ya da bootstrap.yml dosyasına yapılan aşağıdaki tanımlamalarla çevre değişkenleri yönetilebilir.

  • QUARTZ_JDBC_JOB_STORE_SCHEMA (schema-name): Scheduler'ın kullandığı şema adıdır (default değerini hibernate'den alınır).

  • "table-prefix": Quartz tablolarına koyulacak ön ektir (default değeri "qrz_"dır).

ÖNEMLİ NOT: Varsayılan olarak her uygulamanın default şemasında quartz tabloları oluşmaktadır. Bazı durumlarda quartz tablolarının tek şemada olması ya da ortak scheduler kullanımları gibi durumlar için bu property'ler yararlıdır. Örneğin; "oauth", "report" ve "bpmn" şemalarımız olsun. Bu şemalarda quartz tabloları olması istenmeyebilir. Bu durumda "schedule" şema ismi tanımlanır. "oauth", "report" ve "bpmn" uygulamalarının quartz scheduler'ların olduğunu varsayalım. Bu uygulamalar için ortak şema kullanmak istediğimizde yukarıdaki "schema-name" property'si değeri kullanılır.

ÖNEMLİ NOT: Varsayılan olarak her uygulamanın içerisine quartz dahil edildiğinde otokonfigurasyon tarafından uygulamanın adı ile tanımlanmış bir scheduler oluşmaktadır. Yani uygulama adı; "scheduler name"'dir. Sebebi; ortak bir arayüzden uygulamadaki planlanmış görevler yönetilmek istendiğinde, uygulama bazlı ayrı yapılmasının sağlanmasıdır.

Kullanım#

Bileşen iki farklı şekilde kullanılabilir.

  • @HvlDistributableScheduled anotasyonu metodun üzerine yazılır ve bu anotasyonun property'leri örnekte görüldüğü gibi doldururulur.

    jobName: Quartz job adıdır.

    jobGroupName: Quartz job grup adıdır.

    jobTriggers: Quartz job trigger tanımıdır.

    triggerType: Quartz job'ın trigger tipidir.

    triggerExp: Quartz job'ın belirlenen trigger tipine uygun expression değeridir.

package tr.com.havelsan.javarch.samples.scheduling;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import tr.com.havelsan.javarch.samples.scheduling.configuration.HvlSchedulingConfiguration;
import tr.com.havelsan.javarch.scheduling.annotation.HvlDistributableScheduled;
import tr.com.havelsan.javarch.scheduling.annotation.HvlJobTrigger;
import tr.com.havelsan.javarch.scheduling.annotation.HvlJobTriggerType;

/**
 * @author javarch
 */
@SpringBootApplication(scanBasePackageClasses = HvlSchedulingConfiguration.class)
public class HvlSchedulingServerApplication {

    public static void main(String[] args) {
        final ConfigurableApplicationContext configurableApplicationContext
                = SpringApplication.run(new Class[]{HvlSchedulingServerApplication.class}, args);

    }

    @HvlDistributableScheduled(
            jobName = "sample-job",
            jobGroupName = "sample-job-group",
            jobTriggers = @HvlJobTrigger(
                    triggerType = HvlJobTriggerType.CRON,
                    triggerExp = "0 15 10 * * ?"
            )
    )
    private static void scheduledWithCron(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("scheduledWithCron triggered.");
    }

    @HvlDistributableScheduled(
            jobName = "sample-job",
            jobGroupName = "sample-job-group",
            jobTriggers = @HvlJobTrigger(
                    triggerType = HvlJobTriggerType.FIXED_RATE,
                    triggerExp = "PT45M"
            )
    )
    private static void scheduledWithSecond(ConfigurableApplicationContext configurableApplicationContext) {
        System.out.println("scheduledWithSecond triggered.");
    }

}
  • Bir diğer kullanım ise; HvlQuartzExecutableJob sınıfını extend eden bir class oluşturmaktır.

package tr.com.havelsan.javarch.samples.scheduling.job;

import org.quartz.JobExecutionContext;
import tr.com.havelsan.javarch.scheduling.quartz.job.HvlQuartzExecutableJob;

import java.util.Set;

public class SampleJob extends HvlQuartzExecutableJob {

    @Override
    protected Integer jobExecutionMaxRetryCount() {
        return 3;
    }

    @Override
    protected Set<Class<? extends Throwable>> whenJobExecutionRetry() {
        return Set.of();
    }

    @Override
    protected void executeJobInstance(JobExecutionContext jobExecutionContext) {
        System.err.println("job executed.");
    }
}
Ardından bu class, aşağıdaki örnekte görüldüğü gibi JobBuilder'a tanımlanır. TriggerBuilder bu tanımı job parametresi olarak alır ve bu tanımlar quartz scheduler'ına verilir.
package tr.com.havelsan.javarch.samples.scheduling.configuration;

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import tr.com.havelsan.javarch.configuration.HvlBaseConfiguration;
import tr.com.havelsan.javarch.samples.scheduling.configuration.constant.HvlSchedulingConfigurationConstant;
import tr.com.havelsan.javarch.samples.scheduling.job.SampleJob;

/**
 * @author javarch
 */
@Configuration
@ComponentScan(basePackages = {HvlSchedulingConfigurationConstant.BASE_PACKAGE})
public class HvlSchedulingConfiguration extends HvlBaseConfiguration {

    @Bean
    public JobDetail sampleJobDetail() {
        return JobBuilder.newJob(SampleJob.class)
                .storeDurably()
                .build();
    }

    @Bean
    public Trigger sampleTrigger() {
        return TriggerBuilder.newTrigger()
                .forJob(sampleJobDetail())
                .withIdentity("triggerName", "group1")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10)
                        .repeatForever())
                .build();
    }

    @Bean
    public SchedulerFactoryBean schedulerFactory(Trigger sampleTrigger, JobDetail sampleJobDetail) {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setJobDetails(sampleJobDetail);
        schedulerFactoryBean.setTriggers(sampleTrigger);
        return schedulerFactoryBean;
    }

}