Skip to content

fix(weather): resilient per-zone/multi-city weather under Open-Meteo 429#378

Merged
bartzbeielstein merged 1 commit into
developfrom
fix/per-zone-weather-429-throttle
Jun 13, 2026
Merged

fix(weather): resilient per-zone/multi-city weather under Open-Meteo 429#378
bartzbeielstein merged 1 commit into
developfrom
fix/per-zone-weather-429-throttle

Conversation

@bartzbeielstein

Copy link
Copy Markdown
Collaborator

What

Hotfix for the 22.4.0 per-zone weather feature. A real four-zone run with --per-zone-weather crashed with:

429 Client Error ... (Open-Meteo archive rate limit)
ValueError: frame 2 has a different index from frame 0

The ValueError escaped on_weather_failure="skip" and aborted the run.

Fix (two parts)

  1. Catchable failure. When a 429 sends one city to differently-ranged fallback data, population_weighted_average raises a bare ValueError. The multi-city combine in weather/features.py now re-raises it as WeatherFetchError (a ValueError subclass), so the configured skip/raise policy governs it — "skip" degrades to no-weather instead of crashing.
  2. Throttling. A process-wide minimum spacing between Open-Meteo requests (_throttle_open_meteo; default 0.5 s, env SPOTFORECAST2_WEATHER_MIN_REQUEST_INTERVAL) spreads the per-zone burst under the rate limit. The urllib3 retry is bumped to total=5/backoff=2 and honours Retry-After. Request timing only — never the data, so determinism is preserved.

tests/conftest.py disables the throttle for the network-mocked suite. New tests cover the ValueErrorWeatherFetchError conversion and the throttle spacing.

Verification (all green locally)

  • uv run pytest tests/ -q — 2638 passed, 1 skipped
  • uv run ruff check src/ tests/ — clean
  • uv run reuse lint — clean
  • uv run quartodoc build && quartodoc interlinks && quarto render --no-cache — full site render, exit 0

Internal-only fix; no public API surface change.

🤖 Generated with Claude Code

…o 429

Per-zone weather (22.4.0) fetches many cities; a burst trips Open-Meteo's
archive rate limit (429). Two problems are fixed:

1. Catchable failure. When a 429 sends one city to differently-ranged
   fallback data, population_weighted_average raises a bare ValueError that
   escaped on_weather_failure="skip" and crashed the run. The multi-city
   combine now re-raises it as WeatherFetchError (a ValueError subclass), so
   the configured skip/raise policy governs it — "skip" degrades to
   no-weather instead of crashing.

2. Throttling. A process-wide minimum spacing between Open-Meteo requests
   (_throttle_open_meteo; default 0.5 s, env
   SPOTFORECAST2_WEATHER_MIN_REQUEST_INTERVAL) spreads the per-zone burst
   under the limit; the urllib3 retry is bumped to total=5/backoff=2 and
   honours Retry-After. Affects request timing only, never the data —
   determinism preserved.

tests/conftest.py disables the throttle for the network-mocked suite. New
tests cover the ValueError->WeatherFetchError conversion and the throttle
spacing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
wait = _MIN_REQUEST_INTERVAL_S - (monotonic() - _LAST_REQUEST_MONOTONIC)
if wait > 0:
sleep(wait)
_LAST_REQUEST_MONOTONIC = monotonic()
@bartzbeielstein bartzbeielstein merged commit 787da50 into develop Jun 13, 2026
10 checks passed
@bartzbeielstein bartzbeielstein deleted the fix/per-zone-weather-429-throttle branch June 13, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants