Files
loogle-scripts/services/telegram-bot/open_meteo_client.py

93 lines
2.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Shared Open-Meteo HTTP client with retries and sane timeouts.
Use for all calls to Open-Meteo APIs to reduce transient timeouts/502s.
"""
from __future__ import annotations
from typing import Dict, Optional, Tuple
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
DEFAULT_TIMEOUT: Tuple[int, int] = (5, 25) # connect, read
_SESSION_CACHE: dict[tuple, requests.Session] = {}
def _session_key(headers: Optional[Dict[str, str]], retries: int, backoff: float) -> tuple:
headers_key = tuple(sorted(headers.items())) if headers else ()
return headers_key, retries, backoff
def get_open_meteo_session(
headers: Optional[Dict[str, str]] = None,
retries: int = 3,
backoff: float = 0.8,
) -> requests.Session:
key = _session_key(headers, retries, backoff)
if key in _SESSION_CACHE:
return _SESSION_CACHE[key]
retry = Retry(
total=retries,
connect=retries,
read=retries,
status=retries,
status_forcelist=(429, 500, 502, 503, 504),
allowed_methods=frozenset(["GET"]),
backoff_factor=backoff,
raise_on_status=False,
respect_retry_after_header=True,
)
adapter = HTTPAdapter(max_retries=retry)
session = requests.Session()
session.mount("https://", adapter)
session.mount("http://", adapter)
if headers:
session.headers.update(headers)
_SESSION_CACHE[key] = session
return session
def configure_open_meteo_session(
session: requests.Session,
headers: Optional[Dict[str, str]] = None,
retries: int = 3,
backoff: float = 0.8,
) -> requests.Session:
retry = Retry(
total=retries,
connect=retries,
read=retries,
status=retries,
status_forcelist=(429, 500, 502, 503, 504),
allowed_methods=frozenset(["GET"]),
backoff_factor=backoff,
raise_on_status=False,
respect_retry_after_header=True,
)
adapter = HTTPAdapter(max_retries=retry)
session.mount("https://", adapter)
session.mount("http://", adapter)
if headers:
session.headers.update(headers)
return session
def open_meteo_get(
url: str,
params: Optional[Dict] = None,
headers: Optional[Dict[str, str]] = None,
timeout: Tuple[int, int] = DEFAULT_TIMEOUT,
retries: int = 3,
backoff: float = 0.8,
) -> requests.Response:
session = get_open_meteo_session(headers=headers, retries=retries, backoff=backoff)
return session.get(url, params=params, timeout=timeout)