Dua minggu setelah pipeline berjalan, pertanyaan yang muncul bukan “apakah malam ini sukses” melainkan “berapa baris yang biasanya diproses, dan kapan angkanya mulai menyimpang”. Pertanyaan seperti itu hanya bisa dijawab bila setiap eksekusi meninggalkan jejak yang terstruktur. Kita memakai dua buku yang berbeda: data/state/state.json mencatat keadaan per tanggal (watermark), sedangkan data/state/runs/ menyimpan satu manifest JSON per eksekusi. Buku pertama menjawab “tanggal apa yang sudah selesai”; buku kedua menjawab “apa yang terjadi pada setiap percobaan”.

Checksum sebagai Sidik Jari #

Fungsi sha256_hex menggabungkan baris-baris terurut menjadi satu nilai:

python src/monitoring.py — checksum
def sha256_hex(baris: Iterable[str]) -> str:
    """SHA-256 atas baris teks; tiap baris diakhiri newline."""
    h = hashlib.sha256()
    for b in baris:
        h.update((b + "\n").encode("utf-8"))
    return h.hexdigest()

Baris fact dibentuk oleh load._baris_fact dengan ORDER BY order_id, dan angka uang diformat dua desimal lewat printf('%.2f', ...). Dengan demikian checksum mencerminkan isi baris, terlepas dari kapan baris itu dimuat. Checksum inilah yang membedakan “jumlahnya kebetulan sama” dari “isinya benar-benar identik” pada bukti Bagian 5.

Manifest Eksekusi #

Setiap run_for_date diakhiri satu manifest. Strukturnya adalah dataclass RunManifest dengan kolom: run_id, status, waktu mulai dan selesai, durasi milidetik, jumlah baris per tahap, checksum, berkas gold, dan galat bila gagal. Nama berkasnya mengikuti run_id, misalnya run-2026-11-02-075011.json. Tabrakan nama dalam satu detik yang sama diselesaikan dengan sufiks -2, -3, dan seterusnya.

Isi ketiga manifest untuk tanggal 2026-11-02 telah kita lihat pada Bagian 5; berikut manifest kegagalannya:

Output yang Dihasilkan:

text
== manifest kegagalan 2026-11-05 ==
run-2026-11-05-075018: status=failed error={'jenis': 'ExtractError', 'pesan': 'partisi tidak ditemukan: data/raw/pesanan_2026-11-05.csv', 'exit_code': 3, 'alert': 'disabled'}
run-2026-11-05-075019: status=failed error={'jenis': 'ExtractError', 'pesan': 'partisi tidak ditemukan: data/raw/pesanan_2026-11-05.csv', 'exit_code': 3, 'alert': 'stub'}

Manifest mencatat juga apakah alert aktif (disabled atau stub), sehingga riwayat eksekusi sekaligus menjadi riwayat konfigurasi. Menjalankan laporan itu semudah:

bash
python3 -m src.monitoring

Output yang Dihasilkan:

text
run_id                    tanggal     status    baris durasi(ms)  checksum fact
-------------------------------------------------------------------------------
run-2026-11-02-075011     2026-11-02  success       8         43  597d2f68aa8be0d…
run-2026-11-02-075015     2026-11-02  skipped       8          0  597d2f68aa8be0d…
run-2026-11-02-075017     2026-11-02  success       8         46  597d2f68aa8be0d…
run-2026-11-03-075012     2026-11-03  success       7         51  10d48d93f879d9a…
run-2026-11-04-075014     2026-11-04  success       8         49  8bd653745eeca46…
run-2026-11-05-075018     2026-11-05  failed        -          0  -
run-2026-11-05-075019     2026-11-05  failed        -          1  -
-------------------------------------------------------------------------------
total eksekusi: 7

Membaca Laporan Status #

Tabel di atas adalah riwayat operasional proyek ini, dan tiga hal langsung terlihat darinya:

  1. Checksum kolom untuk 2026-11-02 sama pada tiga baris. Sukses pertama, lewati, dan sukses ulang menghasilkan isi warehouse yang identik; inilah bukti idempotensi yang dibahas Bagian 5, kali ini terbaca dari sisi monitoring.
  2. Baris gagal menampilkan tanda - pada kolom baris dan checksum, karena eksekusi gagal tidak menghasilkan beban. Durasi 0-1 ms menunjukkan kegagalan terjadi di tahap paling awal.
  3. Durasi sehat berkisar 43-51 ms untuk beban 7-8 baris. Bila suatu hari durasi melonjak dua tingkat besaran, itu pertanda volume sumber berubah atau ada yang perlu diperiksa.

Dua Buku yang Berbeda Peran #

Aspekstate.json (watermark)runs/*.json (manifest)
Kuncinyatanggal partisisatu eksekusi (bisa lebih dari satu per tanggal)
Menjawabtanggal apa yang sudah selesaiapa yang terjadi pada tiap percobaan
Dibaca olehdue_runs pada schedulerbuild_status_report dan penyelidikan kegagalan
Umurdiperbarui, entri lama tetapmenempel terus sebagai riwayat

Pemisahan ini sejalan dengan chapter Pipeline Logging: log per baris berguna untuk menelusuri, sedangkan ringkasan per eksekusi berguna untuk dipantau. Pola Metrics dan Alerting menambahkan pengiriman metrik ke sistem eksternal; pada proyek ini baris manifest sudah berbentuk yang tepat untuk dikirim bila suatu saat diperlukan. Selanjutnya kita memasang pemeriksaan terakhir yang membaca kembali seluruh hasil: validasi dan rekonsiliasi.

Bacaan lanjut: hashlib pada dokumentasi Python dan DuckDB .