@@ -41,9 +41,11 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
4141# under the License.
4242from __future__ import annotations
4343
44+ import asyncio
45+
4446from json import JSONDecodeError
4547from os import environ
46- from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict
48+ from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Optional
4749
4850from httpx import AsyncClient, ConnectTimeout, NetworkError, Response
4951
@@ -53,6 +55,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
5355 API_VERSION_HEADER,
5456 RID_KEY_HEADER,
5557 SUPPORTED_CDI_VERSIONS,
58+ RATE_LIMIT_STATUS_CODE,
5659)
5760from .normalised_url_path import NormalisedURLPath
5861
@@ -70,7 +73,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
7073 __init_called = False
7174 __hosts: List[Host] = []
7275 __api_key: Union[None, str] = None
73- __api_version = None
76+ api_version = None
7477 __last_tried_index: int = 0
7578 __hosts_alive_for_testing: Set[str] = set()
7679
@@ -97,8 +100,8 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
97100 return Querier.__hosts_alive_for_testing
98101
99102 async def get_api_version(self):
100- if Querier.__api_version is not None:
101- return Querier.__api_version
103+ if Querier.api_version is not None:
104+ return Querier.api_version
102105
103106 ProcessState.get_instance().add_state(
104107 AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -124,8 +127,8 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
124127 "to find the right versions"
125128 )
126129
127- Querier.__api_version = api_version
128- return Querier.__api_version
130+ Querier.api_version = api_version
131+ return Querier.api_version
129132
130133 @staticmethod
131134 def get_instance(rid_to_core: Union[str, None] = None):
@@ -141,7 +144,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
141144 Querier.__init_called = True
142145 Querier.__hosts = hosts
143146 Querier.__api_key = api_key
144- Querier.__api_version = None
147+ Querier.api_version = None
145148 Querier.__last_tried_index = 0
146149 Querier.__hosts_alive_for_testing = set()
147150
@@ -224,6 +227,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
224227 method: str,
225228 http_function: Callable[[str], Awaitable[Response]],
226229 no_of_tries: int,
230+ retry_info_map: Optional[Dict[str, int]] = None,
227231 ) -> Any:
228232 if no_of_tries == 0:
229233 raise_general_exception("No SuperTokens core available to query")
@@ -240,6 +244,14 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
240244 Querier.__last_tried_index %= len(self.__hosts)
241245 url = current_host + path.get_as_string_dangerous()
242246
247+ max_retries = 5
248+
249+ if retry_info_map is None:
250+ retry_info_map = {}
251+
252+ if retry_info_map.get(url) is None:
253+ retry_info_map[url] = max_retries
254+
243255 ProcessState.get_instance().add_state(
244256 AllowedProcessStates.CALLING_SERVICE_IN_REQUEST_HELPER
245257 )
@@ -249,6 +261,20 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
249261 ):
250262 Querier.__hosts_alive_for_testing.add(current_host)
251263
264+ if response.status_code == RATE_LIMIT_STATUS_CODE:
265+ retries_left = retry_info_map[url]
266+
267+ if retries_left > 0:
268+ retry_info_map[url] = retries_left - 1
269+
270+ attempts_made = max_retries - retries_left
271+ delay = (10 + attempts_made * 250) / 1000
272+
273+ await asyncio.sleep(delay)
274+ return await self.__send_request_helper(
275+ path, method, http_function, no_of_tries, retry_info_map
276+ )
277+
252278 if is_4xx_error(response.status_code) or is_5xx_error(response.status_code): # type: ignore
253279 raise_general_exception(
254280 "SuperTokens core threw an error for a "
@@ -266,9 +292,9 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
266292 except JSONDecodeError:
267293 return response.text
268294
269- except (ConnectionError, NetworkError, ConnectTimeout):
295+ except (ConnectionError, NetworkError, ConnectTimeout) as _ :
270296 return await self.__send_request_helper(
271- path, method, http_function, no_of_tries - 1
297+ path, method, http_function, no_of_tries - 1, retry_info_map
272298 )
273299 except Exception as e:
274300 raise_general_exception(e)</ code > </ pre >
@@ -297,7 +323,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
297323 __init_called = False
298324 __hosts: List[Host] = []
299325 __api_key: Union[None, str] = None
300- __api_version = None
326+ api_version = None
301327 __last_tried_index: int = 0
302328 __hosts_alive_for_testing: Set[str] = set()
303329
@@ -324,8 +350,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
324350 return Querier.__hosts_alive_for_testing
325351
326352 async def get_api_version(self):
327- if Querier.__api_version is not None:
328- return Querier.__api_version
353+ if Querier.api_version is not None:
354+ return Querier.api_version
329355
330356 ProcessState.get_instance().add_state(
331357 AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -351,8 +377,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
351377 "to find the right versions"
352378 )
353379
354- Querier.__api_version = api_version
355- return Querier.__api_version
380+ Querier.api_version = api_version
381+ return Querier.api_version
356382
357383 @staticmethod
358384 def get_instance(rid_to_core: Union[str, None] = None):
@@ -368,7 +394,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
368394 Querier.__init_called = True
369395 Querier.__hosts = hosts
370396 Querier.__api_key = api_key
371- Querier.__api_version = None
397+ Querier.api_version = None
372398 Querier.__last_tried_index = 0
373399 Querier.__hosts_alive_for_testing = set()
374400
@@ -451,6 +477,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
451477 method: str,
452478 http_function: Callable[[str], Awaitable[Response]],
453479 no_of_tries: int,
480+ retry_info_map: Optional[Dict[str, int]] = None,
454481 ) -> Any:
455482 if no_of_tries == 0:
456483 raise_general_exception("No SuperTokens core available to query")
@@ -467,6 +494,14 @@ <h2 class="section-title" id="header-classes">Classes</h2>
467494 Querier.__last_tried_index %= len(self.__hosts)
468495 url = current_host + path.get_as_string_dangerous()
469496
497+ max_retries = 5
498+
499+ if retry_info_map is None:
500+ retry_info_map = {}
501+
502+ if retry_info_map.get(url) is None:
503+ retry_info_map[url] = max_retries
504+
470505 ProcessState.get_instance().add_state(
471506 AllowedProcessStates.CALLING_SERVICE_IN_REQUEST_HELPER
472507 )
@@ -476,6 +511,20 @@ <h2 class="section-title" id="header-classes">Classes</h2>
476511 ):
477512 Querier.__hosts_alive_for_testing.add(current_host)
478513
514+ if response.status_code == RATE_LIMIT_STATUS_CODE:
515+ retries_left = retry_info_map[url]
516+
517+ if retries_left > 0:
518+ retry_info_map[url] = retries_left - 1
519+
520+ attempts_made = max_retries - retries_left
521+ delay = (10 + attempts_made * 250) / 1000
522+
523+ await asyncio.sleep(delay)
524+ return await self.__send_request_helper(
525+ path, method, http_function, no_of_tries, retry_info_map
526+ )
527+
479528 if is_4xx_error(response.status_code) or is_5xx_error(response.status_code): # type: ignore
480529 raise_general_exception(
481530 "SuperTokens core threw an error for a "
@@ -493,13 +542,20 @@ <h2 class="section-title" id="header-classes">Classes</h2>
493542 except JSONDecodeError:
494543 return response.text
495544
496- except (ConnectionError, NetworkError, ConnectTimeout):
545+ except (ConnectionError, NetworkError, ConnectTimeout) as _ :
497546 return await self.__send_request_helper(
498- path, method, http_function, no_of_tries - 1
547+ path, method, http_function, no_of_tries - 1, retry_info_map
499548 )
500549 except Exception as e:
501550 raise_general_exception(e)</ code > </ pre >
502551</ details >
552+ < h3 > Class variables</ h3 >
553+ < dl >
554+ < dt id ="supertokens_python.querier.Querier.api_version "> < code class ="name "> var < span class ="ident "> api_version</ span > </ code > </ dt >
555+ < dd >
556+ < div class ="desc "> </ div >
557+ </ dd >
558+ </ dl >
503559< h3 > Static methods</ h3 >
504560< dl >
505561< dt id ="supertokens_python.querier.Querier.get_hosts_alive_for_testing "> < code class ="name flex ">
@@ -553,7 +609,7 @@ <h3>Static methods</h3>
553609 Querier.__init_called = True
554610 Querier.__hosts = hosts
555611 Querier.__api_key = api_key
556- Querier.__api_version = None
612+ Querier.api_version = None
557613 Querier.__last_tried_index = 0
558614 Querier.__hosts_alive_for_testing = set()</ code > </ pre >
559615</ details >
@@ -589,8 +645,8 @@ <h3>Methods</h3>
589645< span > Expand source code</ span >
590646</ summary >
591647< pre > < code class ="python "> async def get_api_version(self):
592- if Querier.__api_version is not None:
593- return Querier.__api_version
648+ if Querier.api_version is not None:
649+ return Querier.api_version
594650
595651 ProcessState.get_instance().add_state(
596652 AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -616,8 +672,8 @@ <h3>Methods</h3>
616672 "to find the right versions"
617673 )
618674
619- Querier.__api_version = api_version
620- return Querier.__api_version </ code > </ pre >
675+ Querier.api_version = api_version
676+ return Querier.api_version </ code > </ pre >
621677</ details >
622678</ dd >
623679< dt id ="supertokens_python.querier.Querier.send_delete_request "> < code class ="name flex ">
@@ -746,6 +802,7 @@ <h2>Index</h2>
746802< li >
747803< h4 > < code > < a title ="supertokens_python.querier.Querier " href ="#supertokens_python.querier.Querier "> Querier</ a > </ code > </ h4 >
748804< ul class ="">
805+ < li > < code > < a title ="supertokens_python.querier.Querier.api_version " href ="#supertokens_python.querier.Querier.api_version "> api_version</ a > </ code > </ li >
749806< li > < code > < a title ="supertokens_python.querier.Querier.get_api_version " href ="#supertokens_python.querier.Querier.get_api_version "> get_api_version</ a > </ code > </ li >
750807< li > < code > < a title ="supertokens_python.querier.Querier.get_hosts_alive_for_testing " href ="#supertokens_python.querier.Querier.get_hosts_alive_for_testing "> get_hosts_alive_for_testing</ a > </ code > </ li >
751808< li > < code > < a title ="supertokens_python.querier.Querier.get_instance " href ="#supertokens_python.querier.Querier.get_instance "> get_instance</ a > </ code > </ li >
0 commit comments