@@ -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
@@ -250,6 +253,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
250253 method: str,
251254 http_function: Callable[[str], Awaitable[Response]],
252255 no_of_tries: int,
256+ retry_info_map: Optional[Dict[str, int]] = None,
253257 ) -> Any:
254258 if no_of_tries == 0:
255259 raise_general_exception("No SuperTokens core available to query")
@@ -266,6 +270,14 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
266270 Querier.__last_tried_index %= len(self.__hosts)
267271 url = current_host + path.get_as_string_dangerous()
268272
273+ max_retries = 5
274+
275+ if retry_info_map is None:
276+ retry_info_map = {}
277+
278+ if retry_info_map.get(url) is None:
279+ retry_info_map[url] = max_retries
280+
269281 ProcessState.get_instance().add_state(
270282 AllowedProcessStates.CALLING_SERVICE_IN_REQUEST_HELPER
271283 )
@@ -275,6 +287,20 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
275287 ):
276288 Querier.__hosts_alive_for_testing.add(current_host)
277289
290+ if response.status_code == RATE_LIMIT_STATUS_CODE:
291+ retries_left = retry_info_map[url]
292+
293+ if retries_left > 0:
294+ retry_info_map[url] = retries_left - 1
295+
296+ attempts_made = max_retries - retries_left
297+ delay = (10 + attempts_made * 250) / 1000
298+
299+ await asyncio.sleep(delay)
300+ return await self.__send_request_helper(
301+ path, method, http_function, no_of_tries, retry_info_map
302+ )
303+
278304 if is_4xx_error(response.status_code) or is_5xx_error(response.status_code): # type: ignore
279305 raise_general_exception(
280306 "SuperTokens core threw an error for a "
@@ -292,9 +318,9 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
292318 except JSONDecodeError:
293319 return response.text
294320
295- except (ConnectionError, NetworkError, ConnectTimeout):
321+ except (ConnectionError, NetworkError, ConnectTimeout) as _ :
296322 return await self.__send_request_helper(
297- path, method, http_function, no_of_tries - 1
323+ path, method, http_function, no_of_tries - 1, retry_info_map
298324 )
299325 except Exception as e:
300326 raise_general_exception(e)</ code > </ pre >
@@ -323,7 +349,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
323349 __init_called = False
324350 __hosts: List[Host] = []
325351 __api_key: Union[None, str] = None
326- __api_version = None
352+ api_version = None
327353 __last_tried_index: int = 0
328354 __hosts_alive_for_testing: Set[str] = set()
329355
@@ -350,8 +376,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
350376 return Querier.__hosts_alive_for_testing
351377
352378 async def get_api_version(self):
353- if Querier.__api_version is not None:
354- return Querier.__api_version
379+ if Querier.api_version is not None:
380+ return Querier.api_version
355381
356382 ProcessState.get_instance().add_state(
357383 AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -377,8 +403,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
377403 "to find the right versions"
378404 )
379405
380- Querier.__api_version = api_version
381- return Querier.__api_version
406+ Querier.api_version = api_version
407+ return Querier.api_version
382408
383409 @staticmethod
384410 def get_instance(rid_to_core: Union[str, None] = None):
@@ -394,7 +420,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
394420 Querier.__init_called = True
395421 Querier.__hosts = hosts
396422 Querier.__api_key = api_key
397- Querier.__api_version = None
423+ Querier.api_version = None
398424 Querier.__last_tried_index = 0
399425 Querier.__hosts_alive_for_testing = set()
400426
@@ -503,6 +529,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
503529 method: str,
504530 http_function: Callable[[str], Awaitable[Response]],
505531 no_of_tries: int,
532+ retry_info_map: Optional[Dict[str, int]] = None,
506533 ) -> Any:
507534 if no_of_tries == 0:
508535 raise_general_exception("No SuperTokens core available to query")
@@ -519,6 +546,14 @@ <h2 class="section-title" id="header-classes">Classes</h2>
519546 Querier.__last_tried_index %= len(self.__hosts)
520547 url = current_host + path.get_as_string_dangerous()
521548
549+ max_retries = 5
550+
551+ if retry_info_map is None:
552+ retry_info_map = {}
553+
554+ if retry_info_map.get(url) is None:
555+ retry_info_map[url] = max_retries
556+
522557 ProcessState.get_instance().add_state(
523558 AllowedProcessStates.CALLING_SERVICE_IN_REQUEST_HELPER
524559 )
@@ -528,6 +563,20 @@ <h2 class="section-title" id="header-classes">Classes</h2>
528563 ):
529564 Querier.__hosts_alive_for_testing.add(current_host)
530565
566+ if response.status_code == RATE_LIMIT_STATUS_CODE:
567+ retries_left = retry_info_map[url]
568+
569+ if retries_left > 0:
570+ retry_info_map[url] = retries_left - 1
571+
572+ attempts_made = max_retries - retries_left
573+ delay = (10 + attempts_made * 250) / 1000
574+
575+ await asyncio.sleep(delay)
576+ return await self.__send_request_helper(
577+ path, method, http_function, no_of_tries, retry_info_map
578+ )
579+
531580 if is_4xx_error(response.status_code) or is_5xx_error(response.status_code): # type: ignore
532581 raise_general_exception(
533582 "SuperTokens core threw an error for a "
@@ -545,13 +594,20 @@ <h2 class="section-title" id="header-classes">Classes</h2>
545594 except JSONDecodeError:
546595 return response.text
547596
548- except (ConnectionError, NetworkError, ConnectTimeout):
597+ except (ConnectionError, NetworkError, ConnectTimeout) as _ :
549598 return await self.__send_request_helper(
550- path, method, http_function, no_of_tries - 1
599+ path, method, http_function, no_of_tries - 1, retry_info_map
551600 )
552601 except Exception as e:
553602 raise_general_exception(e)</ code > </ pre >
554603</ details >
604+ < h3 > Class variables</ h3 >
605+ < dl >
606+ < dt id ="supertokens_python.querier.Querier.api_version "> < code class ="name "> var < span class ="ident "> api_version</ span > </ code > </ dt >
607+ < dd >
608+ < div class ="desc "> </ div >
609+ </ dd >
610+ </ dl >
555611< h3 > Static methods</ h3 >
556612< dl >
557613< dt id ="supertokens_python.querier.Querier.get_hosts_alive_for_testing "> < code class ="name flex ">
@@ -605,7 +661,7 @@ <h3>Static methods</h3>
605661 Querier.__init_called = True
606662 Querier.__hosts = hosts
607663 Querier.__api_key = api_key
608- Querier.__api_version = None
664+ Querier.api_version = None
609665 Querier.__last_tried_index = 0
610666 Querier.__hosts_alive_for_testing = set()</ code > </ pre >
611667</ details >
@@ -670,8 +726,8 @@ <h3>Methods</h3>
670726< span > Expand source code</ span >
671727</ summary >
672728< pre > < code class ="python "> async def get_api_version(self):
673- if Querier.__api_version is not None:
674- return Querier.__api_version
729+ if Querier.api_version is not None:
730+ return Querier.api_version
675731
676732 ProcessState.get_instance().add_state(
677733 AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -697,8 +753,8 @@ <h3>Methods</h3>
697753 "to find the right versions"
698754 )
699755
700- Querier.__api_version = api_version
701- return Querier.__api_version </ code > </ pre >
756+ Querier.api_version = api_version
757+ return Querier.api_version </ code > </ pre >
702758</ details >
703759</ dd >
704760< dt id ="supertokens_python.querier.Querier.send_delete_request "> < code class ="name flex ">
@@ -834,6 +890,7 @@ <h2>Index</h2>
834890< li >
835891< h4 > < code > < a title ="supertokens_python.querier.Querier " href ="#supertokens_python.querier.Querier "> Querier</ a > </ code > </ h4 >
836892< ul class ="">
893+ < li > < code > < a title ="supertokens_python.querier.Querier.api_version " href ="#supertokens_python.querier.Querier.api_version "> api_version</ a > </ code > </ li >
837894< li > < code > < a title ="supertokens_python.querier.Querier.get_all_core_urls_for_path " href ="#supertokens_python.querier.Querier.get_all_core_urls_for_path "> get_all_core_urls_for_path</ a > </ code > </ li >
838895< 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 >
839896< 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 >
0 commit comments