Skip to content

Status Antrean Scraper yang Jujur: dari Empty sampai Recheck

Adityo Guni Waluyo

Antrean scraper dengan dua status akhir menyembunyikan empat realitas. Pemisahan empty, incomplete, error, plus worklist berbasis umur data menutup celah itu.

Ringkasan

Panen data macet gara-gara status cuma ada ok dan error, jadi halaman yang sukses dimuat tapi kosong nganggur di pending terus. Nambahin retry cuma buang jatah kunjungan, ternyata masalahnya bukan jaringan. Solusinya: perbanyak status jadi empty sama incomplete, tandain pas proses jalan, terus susun daftar recheck dari umur data.

Sesi panen pagi itu berhenti di tempat yang aneh. Belasan kasus yang sudah dikunjungi sehari sebelumnya masih tercatat pending, termasuk satu kasus yang tab biayanya dua kali dibuka dan dua kali kembali kosong. Antrean hanya mengenal dua kata untuk hasil akhir, ok dan error, sehingga halaman yang sukses dimuat tetapi memang tidak berisi dipaksa menempel di status pending tanpa arti.

Dugaan pertama menunjuk ke keandalan jaringan. Rencananya menambah jeda dan batas percobaan ulang, cara klasik menangani kegagalan. Diagnosis itu keliru: halaman yang sukses dimuat tetapi kosong bukan kegagalan, dan mengulangnya lima kali hanya memboros jatah kunjungan per kasus. Setelah jatah habis, kasusnya ditinggalkan tanpa catatan yang bisa dibaca sesi berikutnya.

Perbaikan yang akhirnya diterapkan bergerak ke arah lain. Alih-alih menambah percobaan ulang, antreannya dipaksa jujur: enumerasi status diperluas, penandaan dilakukan saat panen, dan daftar kerja pemeriksaan ulang diturunkan dari umur data.

Perluas Enumerasi Status

Empat realitas bersembunyi di balik dua kata lama, dan masing-masing kini punya namanya sendiri.

  • Status pending berarti unit belum pernah diperiksa sama sekali.
  • Status ok berarti halaman terbaca lengkap sesuai skema.
  • Status error berarti alatnya gagal: timeout, halaman tidak terbuka, sesi mati di tengah jalan.
  • Status empty berarti halaman sukses dimuat tetapi sumbernya memang tidak berisi. Ini keputusan penerbit data, bukan kecelakaan teknis.
  • Status incomplete berarti halaman terbaca tetapi kolom kunci kosong, dan itu kandidat terkuat untuk pemeriksaan ulang.

Dua status terakhir bukan tambahan kosmetik. empty yang ditandai jujur menghentikan siklus percobaan ulang yang sia-sia, sedangkan incomplete menyelamatkan kunjungan setengah berhasil agar tidak tercatat sebagai gagal total. Aturan penandaannya satu: tulis status di tempat kejadian, saat unit selesai diproses, bukan dalam satu batch di akhir sesi.

def tandai_hasil(unit, muatan, kolom_kunci):
    if muatan is None:
        status = "error"        # alat gagal: timeout, halaman tidak terbuka
    elif not muatan.strip():
        status = "empty"        # sukses dimuat, sumbernya memang kosong
    elif not all(k in muatan for k in kolom_kunci):
        status = "incomplete"   # terbaca, kolom kunci hilang
    else:
        status = "ok"
    queue.mark(unit, status)    # ditulis di tempat kejadian
    return status

Antrean sendiri tetap berupa berkas SQLite tunggal, basis data ringan yang berjalan tanpa proses server terpisah [1], sehingga satu modul kecil cukup untuk memegang seluruh mesin status.

Turunkan Worklist dari Umur Data

Sesi pemeriksaan ulang yang disusun dari ingatan pasti bocor. Kasus yang terlintas akan dijamah, kasus yang luput akan tertidur selamanya. Karena itu daftar kerjanya tidak dihafal, melainkan diturunkan dari data: semua unit berstatus pending, ditambah unit empty dan incomplete yang usianya melewati ambang tertentu.

# daftar kerja pemeriksaan ulang: pending + empty/incomplete berumur 14 hari
python3 queue.py recheck --days 14

Umur dipakai sebagai kriteria karena ketiga kelompok itu punya alasan berbeda untuk diperiksa ulang. Unit pending adalah pekerjaan yang belum selesai. Unit empty bisa saja berisi besok karena pengadilan menerbitkan datanya belakangan. Unit incomplete bisa saja sudah diperbaiki di sisi sumber. Bahkan unit ok ikut menua datanya, dan ambang hari itulah yang menentukan kapan ia layak dilihat lagi.

Baca Distribusinya Setiap Sesi

Setiap sesi dibuka dengan laporan status, bukan dengan navigasi acak. Distribusi yang sehat didominasi ok dengan error mendekati nol. Lonjakan incomplete menunjuk ke perubahan struktur halaman, sedangkan empty yang mendadak mendominasi menunjuk ke perubahan alamat atau parameter. Dua bacaan itu mengarahkan perbaikan ke parser atau ke daftar URL tanpa membongkar log jaringan.

Pola pemodelan yang sama sudah lama dipakai sistem yang lebih tua. Instance Task di Airflow membawa state yang terdefinisi sepanjang siklus hidupnya, dari antrian sampai selesai, sehingga keputusan ulang dan ketergantungan diambil dari state, bukan dari tebakan [2]. RFC 3339 menyediakan bagian khusus berjudul Unknown Local Offset Convention, slot resmi untuk mencatat waktu tanpa memalsukan zona yang tidak diketahui [4]. Python memisahkan objek waktu aware dan naive dengan alasan yang sama; objek naive memang lebih praktis, tetapi kehilangan kemampuan menempatkan dirinya di garis waktu [3].

Kontrak sesi sekarang tertulis di dokumen proyek: mulai dari laporan status, ambil pekerjaan dari daftar kerja, tandai saat panen. Satu kata status tambahan ternyata murah, dan ia membeli sesuatu yang tidak dibeli oleh percobaan ulang: pembeda antara sumber yang kosong dan alat yang gagal.

Sumber

[1] sqlite3, Python Documentation
[2] Tasks, Apache Airflow Documentation
[3] datetime, Python Documentation
[4] RFC 3339, Date and Time on the Internet: Timestamps

Artikel terkait