Files
databisnisid/scan_loop.py
T
proitlab 656f26085f T18: stack swarm docker — image web+scan, scan_loop.py, mariadb bind-mount server5.saltis.id
- Dockerfile (web) + Dockerfile.scan (scan; sertakan tzdata) + .dockerignore
- scan_loop.py: jadwal skan SCAN_HOURS (0,8,16 lokal via TZ) + skan-awal SCAN_RUN_ON_START; loop tak keluar; tunggu DB siap
- docker-compose.yml → STACK SWARM produksi (mariadb bind mount /data/db/mariadb/databisnisid/data + placement node.hostname == server5.saltis.id; web :5000; scan); image dari registry git.proit.id/proitlab/databisnisid-{web,scan}
- docker-compose.dev.yml: mariadb uji lokal (127.0.0.1:3306) — pengganti docker-compose.yml lama
- SPEC.md §V18/T18; AGENTS.md runbook swarm + dev compose
- .env.example: TZ/SCAN_HOURS/SCAN_RUN_ON_START/MARIADB_*
2026-08-05 14:26:29 +07:00

84 lines
2.8 KiB
Python

"""Jadwal skan berkala: jalankan get_voters.py pada jam SCAN_HOURS (waktu lokal).
Menunggu hingga batas jam berikutnya dalam daftar `SCAN_HOURS` (default 0,8,16)
lalu memanggil `get_voters.main()`. Loop tak pernah keluar — service dijaga
hidup oleh restart_policy swarm. Gagal skan dicatat lalu lanjut ke batas
berikutnya (tidak membunuh loop). `TZ` env menentukan jam lokal via
`datetime.now()` (libc); image Dockerfile.scan sudah menyertakan tzdata.
`SCAN_RUN_ON_START` (default 1): skan sekali saat container start setelah
basis data siap — penting agar tabel voters langsung ada (dashboard ⊥ 500
sebelum batas jam pertama).
"""
import os
import time
from datetime import datetime, timedelta
import db
import get_voters
def parse_hours(raw):
"""Daftar jam integer dari string CSV, diurutkan naik."""
hours = sorted({int(h) for h in raw.split(',') if h.strip()})
if not hours or not all(0 <= h <= 23 for h in hours):
raise ValueError(f'SCAN_HOURS tak valid: {raw!r}')
return hours
def next_boundary(now, hours):
"""datetime berikutnya pada jam-jam `hours` yang lebih besar dari `now`."""
for h in hours:
cand = now.replace(hour=h, minute=0, second=0, microsecond=0)
if cand > now:
return cand
# semua jam hari ini sudah lewat → besok jam pertama
nxt = now + timedelta(days=1)
return nxt.replace(hour=hours[0], minute=0, second=0, microsecond=0)
def _wait_db(timeout=120):
"""Tunggu basis data siap (mariadb baru boot) sebelum skan awal."""
start = time.monotonic()
while time.monotonic() - start < timeout:
try:
db.queryone('SELECT 1')
return
except Exception:
time.sleep(3)
raise RuntimeError('basis data tak siap setelah menunggu')
def _run_scan(label):
print(f'[{label}] memulai skan...', flush=True)
try:
rc = get_voters.main()
except Exception as exc:
print(f'[Error] Skan gagal: {exc}', flush=True)
return
if rc != 0:
print(f'[Peringatan] get_voters keluar dengan kode {rc}', flush=True)
def main():
hours = parse_hours(os.getenv('SCAN_HOURS', '0,8,16'))
run_on_start = os.getenv('SCAN_RUN_ON_START', '1').lower() not in ('0', 'false', 'no')
print(f'Jadwal skan: jam {", ".join(str(h) for h in hours)} (waktu lokal); '
f'skan-awal: {"ya" if run_on_start else "tidak"}')
if run_on_start:
_wait_db()
_run_scan('skan awal')
while True:
now = datetime.now()
target = next_boundary(now, hours)
wait = (target - now).total_seconds()
print(f'{now.isoformat(timespec="seconds")} tidur {wait / 3600:.2f} jam '
f'sampai {target.isoformat(timespec="seconds")}', flush=True)
time.sleep(max(wait, 0))
_run_scan('skan terjadwal')
if __name__ == '__main__':
main()