Pipeline batch berjalan berulang: setiap 15 menit, setiap jam, atau setiap hari pada tengah malam. Sekilas penjadwalan terlihat sederhana — “jalankan pipeline ini setiap hari” — tetapi pertanyaan yang mengikuti tidak sesederhana itu: jam berapa tepatnya sebuah run terjadi, periode data mana yang diproses, apa yang terjadi ketika workflow dimatikan tiga hari lalu dinyalakan kembali, dan bagaimana timezone ikut menentukan jadwal? Chapter ini membedah model penjadwalan yang dipakai workflow orchestrator, dari cron expression sampai konsep data interval yang menjadi fondasi cara kerja Airflow.

Interval vs Cron Expression #

Dua model jadwal mendominasi. Interval menyatakan “setiap N satuan waktu”: titik jalankan berikutnya adalah titik sebelumnya ditambah N, berpatokan pada start_date — bukan pada kalender. Cron expression terdiri dari lima field (menit, jam, tanggal bulanan, bulan, hari minggu) dan menempel pada kalender: jadwal “setiap Senin pukul 06:00” atau “tanggal 1 setiap bulan” hanya bisa diungkapkan dengan cron, bukan interval murni.

Kebutuhan jadwalInterval (timedelta)Cron
Setiap 15 menitminutes=15*/15 * * * *
Setiap jam tepathours=10 * * * *
Setiap hari pukul 00:00days=1 (dari start_date)0 0 * * *
Setiap Senin pukul 06:00tidak bisa dijangkarkan ke kalender0 6 * * 1
Tanggal 1 setiap bulantidak bisa dijangkarkan ke kalender0 0 1 * *

Perhatikan baris “setiap hari”: interval days=1 berjalan dari start_date — bila workflow dibuat pukul 14:37, run harian selamanya terjadi pukul 14:37 — sedangkan cron 0 0 * * * selalu jatuh tepat tengah malam. Rujukan lengkap lima field cron beserta operator khusus tersedia di halaman Wikipedia cron .

Data Interval dan Logical Date #

Run harian untuk tanggal 15 Januari seharusnya memproses data periode 15 Januari 00:00 hingga 16 Januari 00:00 — disebut data interval. Eksekusinya justru dilakukan di akhir interval (16 Januari pukul 00:00) supaya seluruh data periode tersebut sudah tersedia di sumber. Airflow menamai awal interval sebagai logical date: tanggal datanya, bukan tanggal eksekusinya.

KonsepNilai untuk run 15 Januari
data_interval_start2026-01-15 00:00
data_interval_end2026-01-16 00:00
logical date2026-01-15 00:00
waktu eksekusi nyata2026-01-16 00:00

Catchup: Menyusul Run yang Terlewat #

Bayangkan DAG harian dengan start_date 1 Desember baru diaktifkan pada 10 Desember: sembilan run tertunda. Dengan catchup=True (perilaku bawaan Airflow), scheduler menjalankan kesembilan run tersebut berurutan dari yang paling lama. Dengan catchup=False, scheduler melewati run historis dan hanya menjalankan run terbaru. Pilihannya bergantung pada sifat pipeline: bila task idempotent dan sumber data historis lengkap, catchup aman dijalankan; bila sumber hanya menyimpan data terbaru, catchup hanya membuang sumber daya — pakai catchup=False lalu lengkapi periode lama secara manual lewat backfill.

Timezone #

Jadwal ditafsirkan dalam timezone tertentu, dan UTC adalah default sekaligus pilihan paling aman. Wilayah WIB (UTC+7) tidak mengenal daylight saving time sehingga bebas dari persoalan jam berulang. Wilayah dengan pergantian DST — sebagian Eropa dan Amerika — bisa mengalami jam yang muncul dua kali atau terlewat sama sekali saat transisi, sehingga run bisa dobel atau hilang. Praktik umum: definisikan jadwal dalam UTC, lalu konversi ke waktu lokal hanya saat penyajian laporan.

Backfill vs Catchup #

Keduanya sama-sama menjalankan run historis, tetapi pemicunya berbeda:

AspekCatchupBackfill
Pemicuscheduler, otomatismanusia, perintah eksplisit
Rentangsejak start_date hingga run terkinirentang bebas yang ditentukan
Momensaat DAG diaktifkan atau dilanjutkankapan saja, biasanya setelah perbaikan

Catchup terjadi karena scheduler mengejar keterlambatan aktivasi; backfill adalah keputusan sadar untuk memproses ulang periode tertentu. Perilaku catchup, data interval, dan logical date terdokumentasi di dokumentasi Apache Airflow , sementara Chapter Backfill membedah persyaratan dan strateginya.

Kalkulator next_run Cron Mini #

Di produksi, library seperti croniter menangani parsing cron lengkap. Untuk memahami mekanismenya, kita tulis parser mini yang mendukung subset cron — field *, angka tetap, dan */langkah pada menit dan jam — cukup untuk pola “setiap N menit”, “setiap jam pada menit tertentu”, dan “setiap hari pada jam tertentu”. Strateginya: mulai dari waktu sekarang, buang detiknya, lalu maju menit demi menit sampai menit dan jam keduanya cocok.

python
"""Penjadwal mini: kalkulasi next_run untuk subset cron 5-field."""
from datetime import datetime, timedelta


def cocok_field(ekspresi, nilai):
    # mendukung "*", angka tetap, dan "*/langkah"
    if ekspresi == "*":
        return True
    if ekspresi.startswith("*/"):
        langkah = int(ekspresi[2:])
        return nilai % langkah == 0
    return nilai == int(ekspresi)


def next_run(ekspresi, mulai):
    menit, jam = ekspresi.split()[:2]
    kandidat = mulai.replace(second=0, microsecond=0)
    for _ in range(24 * 60):
        if cocok_field(menit, kandidat.minute) and cocok_field(jam, kandidat.hour):
            return kandidat
        kandidat += timedelta(minutes=1)
    raise ValueError("ekspresi tidak cocok dalam 24 jam")


sekarang = datetime(2026, 1, 15, 10, 7, 30)
for ekspresi in ["*/15 * * * *", "30 14 * * *", "0 6 * * *"]:
    print(f"{ekspresi:12} dari {sekarang:%H:%M} -> {next_run(ekspresi, sekarang)}")

Output yang Dihasilkan:

text
*/15 * * * * dari 10:07 -> 2026-01-15 10:15:00
30 14 * * *  dari 10:07 -> 2026-01-15 14:30:00
0 6 * * *    dari 10:07 -> 2026-01-16 06:00:00

Mari kita telaah baris-baris kode di atas:

  1. Baris 5-12 (cocok_field): satu field cron diperiksa terhadap nilai aktual — * selalu cocok, */n cocok bila nilai habis dibagi n (menit 15, 30, 45 cocok untuk */15), dan angka tetap cocok hanya pada nilai yang persis sama.
  2. Baris 16 (ekspresi.split()[:2]): hanya dua field pertama yang dipakai; field tanggal, bulan, dan hari minggu diperlakukan sebagai * supaya contoh tetap ringkas.
  3. Baris 17: detik dan mikrodetik dibuang agar kandidat selalu jatuh pada menit penuh.
  4. Baris 18-21 (pencarian berurut): kandidat maju satu menit per langkah, maksimal 24 × 60 = 1440 langkah; pola 0 6 * * * yang sudah lewat pada pukul 10:07 ditemukan keesokan harinya.
  5. Baris 25-27: tiga jadwal dihitung dari titik waktu yang sama — */15 menghasilkan jeda 8 menit, 30 14 menunggu hingga siang, dan 0 6 bergeser ke besok.

Jadwal yang benar memastikan run dipicu pada waktu yang tepat, tetapi tidak menjamin eksekusinya sukses — gangguan jaringan dan galat data tetap terjadi di dunia nyata. Kebijakan menghadapi kegagalan tersebut adalah pokok bahasan Chapter Retries dan Timeouts.