Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 43 additions & 7 deletions firebase_admin/_http_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

from __future__ import annotations
import logging
import time
import asyncio
from typing import Any, Dict, Generator, Optional, Tuple, Union
import httpx
import requests.adapters
Expand Down Expand Up @@ -46,7 +48,6 @@
DEFAULT_HTTPX_RETRY_CONFIG = HttpxRetry(
max_retries=4, status_forcelist=[500, 503], backoff_factor=0.5)


DEFAULT_TIMEOUT_SECONDS = 120

METRICS_HEADERS = {
Expand Down Expand Up @@ -132,9 +133,26 @@ class call this method to send HTTP requests out. Refer to
if 'timeout' not in kwargs:
kwargs['timeout'] = self.timeout
kwargs.setdefault('headers', {}).update(METRICS_HEADERS)
resp = self._session.request(method, self.base_url + url, **kwargs)
resp.raise_for_status()
return resp

retries = 0
max_retries = 4
backoff_factor = 0.5

while retries <= max_retries:
try:
resp = self._session.request(method, self.base_url + url, **kwargs)
resp.raise_for_status()
return resp
except requests.exceptions.HTTPError as http_err:
if resp.status_code in [400, 401, 403]:
retries += 1
if retries > max_retries:
raise
retry_after = int(resp.headers.get('Retry-After', 0))
sleep_time = backoff_factor * (2 ** (retries - 1)) + retry_after
time.sleep(sleep_time)
else:
raise

def headers(self, method, url, **kwargs):
resp = self.request(method, url, **kwargs)
Expand Down Expand Up @@ -329,8 +347,26 @@ class call this method to send HTTP requests out. Refer to
"""
if 'timeout' not in kwargs:
kwargs['timeout'] = self.timeout
resp = await self._async_client.request(method, self.base_url + url, **kwargs)
return resp.raise_for_status()

retries = 0
max_retries = 4
backoff_factor = 0.5

while retries <= max_retries:
try:
resp = await self._async_client.request(method, self.base_url + url, **kwargs)
resp.raise_for_status()
return resp
except httpx.HTTPStatusError as http_err:
if resp.status_code in [400, 401, 403]:
retries += 1
if retries > max_retries:
raise
retry_after = int(resp.headers.get('Retry-After', 0))
sleep_time = backoff_factor * (2 ** (retries - 1)) + retry_after
await asyncio.sleep(sleep_time)
else:
raise

async def headers(self, method: str, url: str, **kwargs: Any) -> httpx.Headers:
resp = await self.request(method, url, **kwargs)
Expand All @@ -354,4 +390,4 @@ def parse_body(self, resp: httpx.Response) -> Any:
return resp.json()

async def aclose(self) -> None:
await self._async_client.aclose()
await self._async_client.aclose()