Episode ini membahas job terjadwal di Quarkus: Quarkus Scheduler dengan @Scheduled, membangun batch processing, konfigurasi task executor dan concurrency control, hingga monitoring job dan retry handling.

Banyak pekerjaan backend terjadi tanpa request pengguna: mengirim email, membersihkan file kadaluarsa, menarik data dari API eksternal, atau menghasilkan laporan harian. Pekerjaan seperti ini dijalankan secara terjadwal di latar belakang.
Episode 11 membahas Quarkus Scheduler untuk task terjadwal, cara membangun batch processing yang andal, konfigurasi task executor dan concurrency control, serta monitoring job dan strategi retry.
./mvnw quarkus:add-extension -Dextensions=schedulerPerintah ./mvnw quarkus:add-extension -Dextensions=scheduler menambahkan dependency scheduler ke project.
Metode yang ditandai @Scheduled dijalankan otomatis oleh scheduler:
import io.quarkus.scheduler.Scheduled;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class ReportJob {
@Scheduled(every = "60s")
void buatLaporan() {
System.out.println("Membuat laporan terjadwal");
}
}@Scheduled(every = "60s") menjalankan metode setiap 60 detik. Format durasi memakai ISO 8601 — 10s, 1m, 1h, atau kombinasi.
Untuk jadwal yang lebih presisi, gunakan cron:
import io.quarkus.scheduler.Scheduled;
@Scheduled(cron = "0 30 2 * * ?")
void backupMalam() {
// berjalan setiap hari pukul 02:30
}Expression "0 30 2 * * ?" berarti detik 0, menit 30, jam 2, setiap hari. Cron Quarkus memakai format Quartz — enam atau tujuh field termasuk detik.
Batch processing sebaiknya memproses data dalam kelompok kecil agar tidak menghabiskan memory. Pola pagination sangat berguna:
import io.quarkus.hibernate.orm.panache.PanacheQuery;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
@ApplicationScoped
public class CleanupJob {
@Inject
SessionRepository sessionRepository;
@Scheduled(cron = "0 0 4 * * ?")
@Transactional
void bersihkanSessionKadaluarsa() {
int halaman = 0;
int batchSize = 500;
List<Session> batch;
do {
PanacheQuery<Session> query =
sessionRepository.find("expiredAt < ?1", now());
batch = query.range(halaman * batchSize,
(halaman + 1) * batchSize - 1).list();
sessionRepository.delete(batch);
halaman++;
} while (!batch.isEmpty());
}
}Pola query.range(start, end) memproses data dalam chunk 500 baris. @Transactional pada metode batch membuat satu transaksi per eksekusi — jika gagal di tengah, seluruh batch di-rollback.
Quarkus Scheduler berjalan di atas executor:
quarkus.scheduler.threads=5
quarkus.scheduler.overdue-grace-period=30Squarkus.scheduler.threads=5 menentukan jumlah thread yang tersedia untuk job. Default 10 cukup untuk kebanyakan kasus.
Job yang berjalan lebih lama dari interval bisa bertumpuk. Kontrol dengan skip saat masih berjalan:
quarkus.scheduler.concurrent-execution.skip-on-concurrent=trueDengan skip-on-concurrent=true, jika eksekusi sebelumnya belum selesai, eksekusi berikutnya dilewati. Alternatif di dalam kode: pakai AtomicBoolean dengan compareAndSet(false, true) untuk mengunci eksekusi dan melepas kunci di blok finally.
Job yang memanggil layanan eksternal bisa gagal sesaat. Gunakan retry:
import io.quarkus.scheduler.Scheduled;
import org.eclipse.microprofile.faulttolerance.Retry;
import jakarta.enterprise.context.ApplicationScoped;
import java.io.IOException;
@ApplicationScoped
public class SyncJob {
@Scheduled(every = "5m")
@Retry(maxRetries = 3, delay = 2000, retryOn = {IOException.class})
void sinkronisasiExternal() {
panggilApiEksternal();
}
}@Retry(maxRetries = 3, delay = 2000) mencoba ulang hingga tiga kali dengan jeda 2 detik saat IOException terjadi.
Quarkus Scheduler mengekspos metrik eksekusi di /q/metrics — cek dengan curl http://localhost:8080/q/metrics | grep scheduler. Metrik mencakup jumlah eksekusi sukses, gagal, dan terlambat. Untuk visibilitas lebih baik, log awal dan akhir setiap job: log yang jelas membantu menelusuri job yang bermasalah di produksi.
Episode 11 membuat aplikasi kalian bekerja sendiri: memahami Quarkus Scheduler dengan @Scheduled dan cron, membangun batch processing dengan pagination dan transaksi, mengontrol concurrency dengan executor dan atomic flag, serta menangani retry dan monitoring job.
Inti yang harus dibawa pulang:
@Scheduled(every = "60s") untuk interval, @Scheduled(cron = "...") untuk jadwal presisi.quarkus.scheduler.concurrent-execution.skip-on-concurrent mencegah overlap.AtomicBoolean memberi kontrol eksekusi bersamaan di dalam kode.@Retry dari SmallRye Fault Tolerance menangani kegagalan sesaat./q/metrics.Di episode 12 selanjutnya kita akan membahas keamanan dasar dan auth — pengenalan Quarkus Security dan HTTP authentication, role-based access control dan identity stores, konfigurasi authentication mechanism, serta proteksi CSRF, CORS, dan secure headers.