Peringatan membandingkan observasi USD/IDR baru yang efektif dengan observasi sebelumnya, bukan waktu polling. Observasi pertama hanya membuat baseline; data lama dan error tidak mengubah state.
- Gunakan
sources["IDR"]daneffective_at["IDR"]untuk menilai IDR. source global adalah ringkasan konservatif semua mata uang. - Observasi pertama hanya baseline. Setelah crossing, beri satu peringatan lalu disarm; rearm hanya setelah observasi valid kembali di bawah ambang.
- Tulis JSON ke file sementara, gunakan mode0600, lalu ganti dengan
os.replaceagar interupsi tidak meninggalkan state setengah jadi. - Gunakan timeout sepuluh detik, simpan kunci di
EXCHANGERATE_API_KEY, dan polling minimal60 detik. Saat429, pertahankan state dan hormatiRetry-After. - Unduh skrip lengkap dan atur threshold serta path state di luar source control. Output hanya ke console lokal.
Model observasi per mata uang
Gunakan sources["IDR"] dan effective_at["IDR"] untuk menilai IDR. source global adalah ringkasan konservatif semua mata uang.
from decimal import Decimaldef idr_observation(payload: dict) -> dict: return { "rate": Decimal(str(payload["rates"]["IDR"])), "source": payload["sources"]["IDR"], "effective_at": payload["effective_at"]["IDR"], "market_session": payload["market_session"], }Tentukan kebijakan crossing
Observasi pertama hanya baseline. Setelah crossing, beri satu peringatan lalu disarm; rearm hanya setelah observasi valid kembali di bawah ambang.
| Situasi | Perubahan state | Peringatan |
|---|---|---|
| Observasi valid pertama | Simpan baseline | Tidak |
| Observasi di bawah ambang | armed=true | Tidak |
| Crossing saat armed | armed=false | Satu |
| Observasi lama/berulang atau error | Pertahankan state | Tidak |
Simpan state dengan aman
Tulis JSON ke file sementara, gunakan mode0600, lalu ganti dengan os.replace agar interupsi tidak meninggalkan state setengah jadi.
import jsonimport osimport tempfilefrom pathlib import Pathdef save_state(path: Path, state: dict) -> None: path.parent.mkdir(parents=True, exist_ok=True) fd, temporary = tempfile.mkstemp(prefix=f".{path.name}.", dir=path.parent, text=True) try: os.fchmod(fd, 0o600) with os.fdopen(fd, "w") as handle: json.dump(state, handle, sort_keys=True) handle.write("\n") os.replace(temporary, path) except Exception: try: os.unlink(temporary) except OSError: pass raiseBatasi jaringan dan kuota
Gunakan timeout sepuluh detik, simpan kunci di EXCHANGERATE_API_KEY, dan polling minimal60 detik. Saat429, pertahankan state dan hormati Retry-After. Interval default lima menit memakai sekitar 8.640 panggilan dalam 30 hari; interval 60 detik sekitar 43.200 dan dapat melebihi kuota bulanan bersama.
Gunakan timeout sepuluh detik, simpan kunci di EXCHANGERATE_API_KEY, dan polling minimal60 detik. Saat429, pertahankan state dan hormati Retry-After.
Jalankan monitor lengkap
Unduh skrip lengkap dan atur threshold serta path state di luar source control. Output hanya ke console lokal. Usia maksimum default adalah satu jam. Atur FX_ALERT_MAX_AGE_SECONDS jika menerima referensi harian atau pasar tutup. python-exchange-rate-alerts.py
chmod 700 python-exchange-rate-alerts.pyexport EXCHANGERATE_API_KEY="your-key"export FX_ALERT_THRESHOLD_PCT="1.0"export FX_ALERT_POLL_SECONDS="300"export FX_ALERT_STATE_PATH="$HOME/.local/state/fx-alert.json"python3 python-exchange-rate-alerts.pyUji kebijakan tanpa menunggu pasar
Uji baseline, crossing, timestamp berulang, data lama, rearm, dan crossing kedua dengan mock jaringan.