diff --git a/infrastructure/solar/google_solar_api_client.py b/infrastructure/solar/google_solar_api_client.py index 307bf46b..fd3c39cf 100644 --- a/infrastructure/solar/google_solar_api_client.py +++ b/infrastructure/solar/google_solar_api_client.py @@ -39,6 +39,24 @@ class GoogleSolarApiClient: self._min_request_interval_seconds = min_request_interval_seconds self._last_request_monotonic: Optional[float] = None + def _await_rate_limit(self) -> None: + """Block until at least ``min_request_interval_seconds`` has elapsed since + this instance's previous call, so the container never exceeds its share of + the fleet's 600 QPM Solar budget. A no-op when the interval is 0 (the + default / interactive path). The call's own latency counts toward the gap + (we sleep only the *remainder*), so we don't double-pay the request time.""" + if self._min_request_interval_seconds <= 0: + return + now = time.monotonic() + if self._last_request_monotonic is not None: + wait = self._min_request_interval_seconds - ( + now - self._last_request_monotonic + ) + if wait > 0: + time.sleep(wait) + now = time.monotonic() + self._last_request_monotonic = now + @staticmethod def _parse_retry_after(response: requests.Response) -> Optional[float]: header = response.headers.get("Retry-After") @@ -55,6 +73,7 @@ class GoogleSolarApiClient: latitude: float, required_quality: Literal["HIGH", "MEDIUM", "LOW"] = "MEDIUM", ) -> dict[str, Any]: + self._await_rate_limit() insights_url = f"{self.base_url}/buildingInsights:findClosest" params: dict[str, str] = { "location.latitude": f"{latitude:.5f}",