Kihagyás

Ütemezett Feladatok - Scheduled Jobs

Minden projekten vannak olyan funkcionális igények amelyeknek felhasználói interakció nélkül automatikusan, meghatározott időben vagy időközönként kell végrehajtódnia.

Például

Havi jelentések, kimutatások előállítása a hónap egy bizonyos napján. Napi egyszeri email értesítések kiküldése stb.

Ezt úgynevezett „Ütemezett Job“-okkal (Scheduled Jobs) valósítjuk meg, melyhez a Quartz ütemezőt használjuk.

A Quartz egyik fontos előnye, hogy működik clusteres környezeten, azaz támogatja, hogy több példányban futtathassuk az alkalmazásokat.

1. Quartz konfiguráció

A Quartz az application.yml fájl spring.quartz szekciójában konfigurálható.

Példa cluesteres Quartz konfiguráció PostgreSQL adatbázis esetén:

spring:
  ...
  quartz:
    job-store-type: jdbc
    wait-for-jobs-to-complete-on-shutdown: true
    properties:
      org:
        quartz:
          jobStore:
            isClustered: true
            driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
            misfireThreshold: 1000
          scheduler:
            instanceName: project-cluster
            instanceId: AUTO

2. Job-ok definiálása

Egy új Quartz Job implementálásához az org.quartz könyvtárban található Job interfészt kell implementálni. Ahhoz, hogy a Job ütemezve legyen a Quartz által egy Trigger és egy JobDetail bean konfigurációt is létre kell hozni az előbbi Job-hoz.

A JobDetail beanben definiáljuk a Job egyedi azonosítóját, míg a Trigger beanben adjuk meg az ütemezéshez szükséges konfigurációt.

Ha a DeleteExpiredSessionsJob osztályt lekövetjük, akkor a gyakorlatban is látható rá példa.

Hierarchikusan egy Job konfigurációja az alábbi módon következik egymásból:

graph LR
    A[Implementáljuk a Job interfészt] --> B[Létrehozunk egy JobDetails beant a Job-hoz];
    B[Létrehozunk egy JobDetails beant a Job-hoz] --> C[Létrehozzuk a Trigger beant a JobDetails-hez];

Jobok ütemezése

Azt, hogy az adott Job pontosan mikor, milyen időközönként fusson le úgynevezett cron kifejezésekkel (cron expression) tudjuk megadni a Trigger konfigurációban.

A Quartz által támogatott cron kifejezésekről részletesebb olvashatsz itt.

2.1 Adott job-hoz custom adat megadása

Adott cron job-nak átadhatunk custom adatot is, ha extra információra van szükség, hogy egy adott cron job lefusson, de a custom-data bekezdés opcionális.

Pl milyen mappába tegye a generált fájlokat.

  cron:
    generate-export-files-job:
      name: generate-export-files-job
      trigger-name: generate-export-files-trigger
      cron-expression: 0 0 3 ? * * *
      custom-data:
        folder: "/opt/generated-files"

Majd pedig a CronJobProperties.CommonCronJobProperties.customData map-ből kell kivenni az adatot és olyan típusúra konvertálni, amilyen tipusú adatként szeretnénk használni.

3. Quartz adatbázis táblák

A Quartz specifikus adatbázis objektumok a liquibase.quartz.init.xml-ben vannak definiálva, amit az alkalmazás első indulásakor a Liquibase futtat le.

A Quartz specifikus táblák a qrtz rövidítéssel vannak prefixelve.

Ezek a táblák tartalmazzák a Quartz működéséhez szükséges adatokat. Pl.: A jobok és triggerek adatait, az ütemezéseket, lockokat stb.

Az egyes táblák szerepéről részletesebben itt olvashatsz.

4. Job-ok manuális újraütemezése

Quartz ütemező használata esetén a már rendszerbe bekerült jobok újraütemezéséhez szükséges lépések az alábbiak.

4.1 Konfiguráció módosítása

Amennyiben az adott jobhoz tartozik ütemezési konfiguráció, pl. cron kifejezés, azt frissítsük be az application.yml fájlban.

    ${JOB_NEVE}:
      name: ${JOB_NEVE}
      trigger-name: ${JOB_TRIGGER_NEVE}
      cron-expression: 0 0 7 ? * * *

4.2 Job adatok törlése az adatbázisból

A trigger típusától függően törlés a megfelelő táblából:

DELETE FROM QRTZ_CRON_TRIGGERS WHERE TRIGGER_NAME = '${JOB_TRIGGER_NEVE}';
vagy
DELETE FROM QRTZ_SIMPLE_TRIGGERS WHERE TRIGGER_NAME = '${JOB_TRIGGER_NEVE}';

Majd a következő általános táblákból törlés:

DELETE FROM QRTZ_TRIGGERS WHERE TRIGGER_NAME = '${JOB_TRIGGER_NEVE}';
DELETE FROM QRTZ_JOB_DETAILS WHERE JOB_NAME = '${JOB_NEVE}';

  • A ${JOB_TRIGGER_NEVE} placeholder helyére értelemszerűen a job trigger nevét kell behelyettesíteni.
  • A ${JOB_NEVE} placeholder helyére értelemszerűen a job nevét kell behelyettesíteni.

4.3. Alkalmazás újraindítása

Ezt követően szükséges az alkalmazás összes példányának újraindítása. Ennek eredményeként az adatbázisba is visszakerülnek a trigger és job rekordok.

4.4 Job-ok újraütemezése admin felületről

Későbbi fejlesztés része lesz

5. Job-ok tesztelése

Tesztet cron jobokra is kell írni, de itt nem a quartz keretrendszert szeretnénk tesztelni, hanem csak azt a service réteget, amit meghív x időpillanatban a quartz. Így csak a Service osztály adott metódusára írjunk teszteket.