stack: service distribute (Dockerfile.dist + distribute_loop.py, harian DISTRIBUTE_HOUR)

This commit is contained in:
proitlab committed 2026-08-05 22:22:24 +07:00
1 parent f77681793f
commit 4e02701887
5 files changed
+130 -7

No files matched your search

+77
View File
@@ -0,0 +1,77 @@
"""Jadwal distribusi harian: jalankan distribute.py pada jam DISTRIBUTE_HOUR.
Menunggu hingga batas `DISTRIBUTE_HOUR` berikutnya (waktu lokal via `TZ`)
lalu memanggil `distribute.main()`. Loop tak pernah keluar — service dijaga
hidup oleh restart_policy swarm. Gagal distribusi dicatat lalu lanjut ke hari
berikutnya (⊥ membunuh loop). Tanpa `VEX_BP_PRIVATE_KEY` run nyata raise
RuntimeError yang jelas — ditangkap, dicetak, dicoba lagi besok.
Berbeda dengan scan: ⊥ ada "distribusi-awal" saat start (SCAN_RUN_ON_START) —
membayar di container start berisiko memakai snapshot basi; distribusi hanya
berjalan pada jam terjadwal.
Scheduler helper (`next_boundary`, `_wait_db`) sengaja diduplikasi dari
`scan_loop.py` (bukan di-import) karena kedua image Docker terpisah:
`Dockerfile.dist` ⊥ membawa `scan_loop.py`/`get_voters.py`.
"""
import os
import time
from datetime import datetime, timedelta
import db
import distribute
def next_boundary(now, hours):
"""datetime berikutnya pada jam-jam `hours` yang lebih besar dari `now`.
Sama dengan `scan_loop.next_boundary` (mirror agar image dist mandiri).
"""
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 loop."""
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_distribute(label):
print(f'[{label}] memulai distribusi...', flush=True)
try:
distribute.main()
except Exception as exc:
print(f'[Error] Distribusi gagal: {exc}', flush=True)
def main():
hour = int(os.getenv('DISTRIBUTE_HOUR', '10'))
if not 0 <= hour <= 23:
raise ValueError(f'DISTRIBUTE_HOUR tak valid: {hour!r}')
print(f'Jadwal distribusi: jam {hour} (waktu lokal)')
_wait_db()
while True:
now = datetime.now()
target = next_boundary(now, [hour])
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_distribute('distribusi terjadwal')
if __name__ == '__main__':
main()