master
1import sys
2
3import asyncio
4from asyncio.exceptions import TimeoutError
5
6import aiohttp
7from aiohttp.client_exceptions import ClientConnectorError
8
9import logging
10
11from typing import List, Optional
12
13
14class BaseClient:
15 def __init__(
16 self,
17 *,
18 host,
19 path,
20 port="",
21 is_ssl=True,
22 timeout=5,
23 retries=6,
24 retry_wait=1,
25 max_timeout=300,
26 max_retry_wait=300,
27 ):
28 self.is_ssl = is_ssl
29 self.host = host
30 self.port = port
31 self.path = path
32 self.timeout = timeout
33 self.retries = retries
34 self.retry_wait = retry_wait
35 self.scheme = "https" if self.is_ssl else "http"
36 self.url = f"{self.scheme}://{self.host}:{self.port}{self.path}"
37 self.logger = logging.getLogger("aiohttp.internal")
38 self.max_timeout = max_timeout
39 self.max_retry_wait = max_retry_wait
40
41 async def retry_after_wait(self, err, func):
42 if self.retries > 0:
43
44 msg = f"Sleeping {self.retry_wait}s. {self.retries} retries remaining"
45 self.logger.warning(msg)
46 await asyncio.sleep(self.retry_wait)
47
48 self.retries = self.retries - 1
49 self.retry_wait = min(self.retry_wait * 2, self.max_retry_wait)
50 return await func()
51 else:
52 msg = f"Retries exhausted"
53 self.logger.error(msg)
54 return (err, None)
55
56 async def get_data(self):
57
58 msg = f"Fetching data from {self.url}"
59 self.logger.info(msg)
60 ct = aiohttp.ClientTimeout(total=self.timeout)
61 async with aiohttp.ClientSession(timeout=ct) as session:
62
63 try:
64 async with session.get(self.url) as resp:
65 data = await resp.json()
66 return (None, data)
67
68 except ClientConnectorError as err:
69 self.logger.error(err)
70 return await self.retry_after_wait(err, self.get_data)
71
72 except TimeoutError as err:
73 self.timeout = self.timeout * 2
74 self.logger.error(
75 f"Request timed out. Retrying with {self.timeout}s timeout"
76 )
77 return await self.retry_after_wait(err, self.get_data)
78
79 except Exception as err:
80 self.logger.error(err)
81 return (err, None)