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.