A fresh GRIB every hour via cron
A common need: keep a local GRIB current without thinking about it. We'll use the one-shot /v1/grib endpoint (no slice to manage), a tiny Python
script that retries politely on rate limits and writes atomically, and a systemd timer to run it hourly.
The script
It reads the token from the environment, retries on 429 honouring Retry-After, exits quietly on 503 (no run published yet), and swaps the
file in atomically so a reader never sees a half-written GRIB.
#!/usr/bin/env python3
"""Pull a fresh WeatherFiles GRIB and write it atomically. Run from cron/systemd."""
import os, sys, time, requests
TOKEN = os.environ["WF_TOKEN"]
OUT = os.environ.get("WF_OUT", "/var/lib/weatherfiles/harm-nl.grib2")
PARAMS = {
"model": "harm-nl",
"params": "wind,gusts,pressure",
"bbox": "3,7,51,54", # west,east,south,north
"time_window_h": 48,
}
def fetch(max_tries=5):
headers = {"Authorization": f"Bearer {TOKEN}"}
for _ in range(max_tries):
r = requests.get("https://api.weatherfiles.com/v1/grib",
headers=headers, params=PARAMS, timeout=180)
if r.status_code == 429: # rate limited - back off
time.sleep(int(r.headers.get("Retry-After", "30")))
continue
if r.status_code == 503: # no run yet - try later
sys.exit(0)
r.raise_for_status()
tmp = OUT + ".tmp"
os.makedirs(os.path.dirname(OUT), exist_ok=True)
with open(tmp, "wb") as f:
f.write(r.content)
os.replace(tmp, OUT) # atomic swap
return
sys.exit("gave up after rate-limit retries")
if __name__ == "__main__":
fetch() Run it hourly with systemd
A oneshot service plus a timer is cleaner than a crontab line and gives you logs
via journalctl:
# /etc/systemd/system/wf-grib.service [Unit] Description=Fetch WeatherFiles GRIB [Service] Type=oneshot Environment=WF_TOKEN=wf_pat_… ExecStart=/usr/bin/python3 /opt/weatherfiles/fetch.py
# /etc/systemd/system/wf-grib.timer [Unit] Description=Fetch WeatherFiles GRIB hourly [Timer] OnCalendar=hourly Persistent=true [Install] WantedBy=timers.target
sudo systemctl enable --now wf-grib.timer systemctl list-timers wf-grib.timer
Hourly is fine even though models run every few hours — the script is cheap, and re-fetching
simply overwrites with the latest run. Keep the cadence at or below your daily quota. For plain cron, call the same script from a crontab line instead.
Next: a Python slice client for managed downloads.