@@ -41,9 +41,11 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
41
41
# under the License.
42
42
from __future__ import annotations
43
43
44
+ import asyncio
45
+
44
46
from json import JSONDecodeError
45
47
from os import environ
46
- from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict
48
+ from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Optional
47
49
48
50
from httpx import AsyncClient, ConnectTimeout, NetworkError, Response
49
51
@@ -53,6 +55,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
53
55
API_VERSION_HEADER,
54
56
RID_KEY_HEADER,
55
57
SUPPORTED_CDI_VERSIONS,
58
+ RATE_LIMIT_STATUS_CODE,
56
59
)
57
60
from .normalised_url_path import NormalisedURLPath
58
61
@@ -70,7 +73,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
70
73
__init_called = False
71
74
__hosts: List[Host] = []
72
75
__api_key: Union[None, str] = None
73
- __api_version = None
76
+ api_version = None
74
77
__last_tried_index: int = 0
75
78
__hosts_alive_for_testing: Set[str] = set()
76
79
@@ -97,8 +100,8 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
97
100
return Querier.__hosts_alive_for_testing
98
101
99
102
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
102
105
103
106
ProcessState.get_instance().add_state(
104
107
AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -124,8 +127,8 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
124
127
"to find the right versions"
125
128
)
126
129
127
- Querier.__api_version = api_version
128
- return Querier.__api_version
130
+ Querier.api_version = api_version
131
+ return Querier.api_version
129
132
130
133
@staticmethod
131
134
def get_instance(rid_to_core: Union[str, None] = None):
@@ -141,7 +144,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
141
144
Querier.__init_called = True
142
145
Querier.__hosts = hosts
143
146
Querier.__api_key = api_key
144
- Querier.__api_version = None
147
+ Querier.api_version = None
145
148
Querier.__last_tried_index = 0
146
149
Querier.__hosts_alive_for_testing = set()
147
150
@@ -250,6 +253,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
250
253
method: str,
251
254
http_function: Callable[[str], Awaitable[Response]],
252
255
no_of_tries: int,
256
+ retry_info_map: Optional[Dict[str, int]] = None,
253
257
) -> Any:
254
258
if no_of_tries == 0:
255
259
raise_general_exception("No SuperTokens core available to query")
@@ -266,6 +270,14 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
266
270
Querier.__last_tried_index %= len(self.__hosts)
267
271
url = current_host + path.get_as_string_dangerous()
268
272
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
+
269
281
ProcessState.get_instance().add_state(
270
282
AllowedProcessStates.CALLING_SERVICE_IN_REQUEST_HELPER
271
283
)
@@ -275,6 +287,20 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
275
287
):
276
288
Querier.__hosts_alive_for_testing.add(current_host)
277
289
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
+
278
304
if is_4xx_error(response.status_code) or is_5xx_error(response.status_code): # type: ignore
279
305
raise_general_exception(
280
306
"SuperTokens core threw an error for a "
@@ -292,9 +318,9 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
292
318
except JSONDecodeError:
293
319
return response.text
294
320
295
- except (ConnectionError, NetworkError, ConnectTimeout):
321
+ except (ConnectionError, NetworkError, ConnectTimeout) as _ :
296
322
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
298
324
)
299
325
except Exception as e:
300
326
raise_general_exception(e)</ code > </ pre >
@@ -323,7 +349,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
323
349
__init_called = False
324
350
__hosts: List[Host] = []
325
351
__api_key: Union[None, str] = None
326
- __api_version = None
352
+ api_version = None
327
353
__last_tried_index: int = 0
328
354
__hosts_alive_for_testing: Set[str] = set()
329
355
@@ -350,8 +376,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
350
376
return Querier.__hosts_alive_for_testing
351
377
352
378
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
355
381
356
382
ProcessState.get_instance().add_state(
357
383
AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -377,8 +403,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
377
403
"to find the right versions"
378
404
)
379
405
380
- Querier.__api_version = api_version
381
- return Querier.__api_version
406
+ Querier.api_version = api_version
407
+ return Querier.api_version
382
408
383
409
@staticmethod
384
410
def get_instance(rid_to_core: Union[str, None] = None):
@@ -394,7 +420,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
394
420
Querier.__init_called = True
395
421
Querier.__hosts = hosts
396
422
Querier.__api_key = api_key
397
- Querier.__api_version = None
423
+ Querier.api_version = None
398
424
Querier.__last_tried_index = 0
399
425
Querier.__hosts_alive_for_testing = set()
400
426
@@ -503,6 +529,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
503
529
method: str,
504
530
http_function: Callable[[str], Awaitable[Response]],
505
531
no_of_tries: int,
532
+ retry_info_map: Optional[Dict[str, int]] = None,
506
533
) -> Any:
507
534
if no_of_tries == 0:
508
535
raise_general_exception("No SuperTokens core available to query")
@@ -519,6 +546,14 @@ <h2 class="section-title" id="header-classes">Classes</h2>
519
546
Querier.__last_tried_index %= len(self.__hosts)
520
547
url = current_host + path.get_as_string_dangerous()
521
548
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
+
522
557
ProcessState.get_instance().add_state(
523
558
AllowedProcessStates.CALLING_SERVICE_IN_REQUEST_HELPER
524
559
)
@@ -528,6 +563,20 @@ <h2 class="section-title" id="header-classes">Classes</h2>
528
563
):
529
564
Querier.__hosts_alive_for_testing.add(current_host)
530
565
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
+
531
580
if is_4xx_error(response.status_code) or is_5xx_error(response.status_code): # type: ignore
532
581
raise_general_exception(
533
582
"SuperTokens core threw an error for a "
@@ -545,13 +594,20 @@ <h2 class="section-title" id="header-classes">Classes</h2>
545
594
except JSONDecodeError:
546
595
return response.text
547
596
548
- except (ConnectionError, NetworkError, ConnectTimeout):
597
+ except (ConnectionError, NetworkError, ConnectTimeout) as _ :
549
598
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
551
600
)
552
601
except Exception as e:
553
602
raise_general_exception(e)</ code > </ pre >
554
603
</ 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 >
555
611
< h3 > Static methods</ h3 >
556
612
< dl >
557
613
< dt id ="supertokens_python.querier.Querier.get_hosts_alive_for_testing "> < code class ="name flex ">
@@ -605,7 +661,7 @@ <h3>Static methods</h3>
605
661
Querier.__init_called = True
606
662
Querier.__hosts = hosts
607
663
Querier.__api_key = api_key
608
- Querier.__api_version = None
664
+ Querier.api_version = None
609
665
Querier.__last_tried_index = 0
610
666
Querier.__hosts_alive_for_testing = set()</ code > </ pre >
611
667
</ details >
@@ -670,8 +726,8 @@ <h3>Methods</h3>
670
726
< span > Expand source code</ span >
671
727
</ summary >
672
728
< 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
675
731
676
732
ProcessState.get_instance().add_state(
677
733
AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -697,8 +753,8 @@ <h3>Methods</h3>
697
753
"to find the right versions"
698
754
)
699
755
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 >
702
758
</ details >
703
759
</ dd >
704
760
< dt id ="supertokens_python.querier.Querier.send_delete_request "> < code class ="name flex ">
@@ -834,6 +890,7 @@ <h2>Index</h2>
834
890
< li >
835
891
< h4 > < code > < a title ="supertokens_python.querier.Querier " href ="#supertokens_python.querier.Querier "> Querier</ a > </ code > </ h4 >
836
892
< 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 >
837
894
< 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 >
838
895
< 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 >
839
896
< 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