@@ -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
@@ -231,6 +234,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
231
234
method: str,
232
235
http_function: Callable[[str], Awaitable[Response]],
233
236
no_of_tries: int,
237
+ retry_info_map: Optional[Dict[str, int]] = None,
234
238
) -> Any:
235
239
if no_of_tries == 0:
236
240
raise_general_exception("No SuperTokens core available to query")
@@ -247,6 +251,14 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
247
251
Querier.__last_tried_index %= len(self.__hosts)
248
252
url = current_host + path.get_as_string_dangerous()
249
253
254
+ max_retries = 5
255
+
256
+ if retry_info_map is None:
257
+ retry_info_map = {}
258
+
259
+ if retry_info_map.get(url) is None:
260
+ retry_info_map[url] = max_retries
261
+
250
262
ProcessState.get_instance().add_state(
251
263
AllowedProcessStates.CALLING_SERVICE_IN_REQUEST_HELPER
252
264
)
@@ -256,6 +268,20 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
256
268
):
257
269
Querier.__hosts_alive_for_testing.add(current_host)
258
270
271
+ if response.status_code == RATE_LIMIT_STATUS_CODE:
272
+ retries_left = retry_info_map[url]
273
+
274
+ if retries_left > 0:
275
+ retry_info_map[url] = retries_left - 1
276
+
277
+ attempts_made = max_retries - retries_left
278
+ delay = (10 + attempts_made * 250) / 1000
279
+
280
+ await asyncio.sleep(delay)
281
+ return await self.__send_request_helper(
282
+ path, method, http_function, no_of_tries, retry_info_map
283
+ )
284
+
259
285
if is_4xx_error(response.status_code) or is_5xx_error(response.status_code): # type: ignore
260
286
raise_general_exception(
261
287
"SuperTokens core threw an error for a "
@@ -273,9 +299,9 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
273
299
except JSONDecodeError:
274
300
return response.text
275
301
276
- except (ConnectionError, NetworkError, ConnectTimeout):
302
+ except (ConnectionError, NetworkError, ConnectTimeout) as _ :
277
303
return await self.__send_request_helper(
278
- path, method, http_function, no_of_tries - 1
304
+ path, method, http_function, no_of_tries - 1, retry_info_map
279
305
)
280
306
except Exception as e:
281
307
raise_general_exception(e)</ code > </ pre >
@@ -304,7 +330,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
304
330
__init_called = False
305
331
__hosts: List[Host] = []
306
332
__api_key: Union[None, str] = None
307
- __api_version = None
333
+ api_version = None
308
334
__last_tried_index: int = 0
309
335
__hosts_alive_for_testing: Set[str] = set()
310
336
@@ -331,8 +357,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
331
357
return Querier.__hosts_alive_for_testing
332
358
333
359
async def get_api_version(self):
334
- if Querier.__api_version is not None:
335
- return Querier.__api_version
360
+ if Querier.api_version is not None:
361
+ return Querier.api_version
336
362
337
363
ProcessState.get_instance().add_state(
338
364
AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -358,8 +384,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
358
384
"to find the right versions"
359
385
)
360
386
361
- Querier.__api_version = api_version
362
- return Querier.__api_version
387
+ Querier.api_version = api_version
388
+ return Querier.api_version
363
389
364
390
@staticmethod
365
391
def get_instance(rid_to_core: Union[str, None] = None):
@@ -375,7 +401,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
375
401
Querier.__init_called = True
376
402
Querier.__hosts = hosts
377
403
Querier.__api_key = api_key
378
- Querier.__api_version = None
404
+ Querier.api_version = None
379
405
Querier.__last_tried_index = 0
380
406
Querier.__hosts_alive_for_testing = set()
381
407
@@ -465,6 +491,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
465
491
method: str,
466
492
http_function: Callable[[str], Awaitable[Response]],
467
493
no_of_tries: int,
494
+ retry_info_map: Optional[Dict[str, int]] = None,
468
495
) -> Any:
469
496
if no_of_tries == 0:
470
497
raise_general_exception("No SuperTokens core available to query")
@@ -481,6 +508,14 @@ <h2 class="section-title" id="header-classes">Classes</h2>
481
508
Querier.__last_tried_index %= len(self.__hosts)
482
509
url = current_host + path.get_as_string_dangerous()
483
510
511
+ max_retries = 5
512
+
513
+ if retry_info_map is None:
514
+ retry_info_map = {}
515
+
516
+ if retry_info_map.get(url) is None:
517
+ retry_info_map[url] = max_retries
518
+
484
519
ProcessState.get_instance().add_state(
485
520
AllowedProcessStates.CALLING_SERVICE_IN_REQUEST_HELPER
486
521
)
@@ -490,6 +525,20 @@ <h2 class="section-title" id="header-classes">Classes</h2>
490
525
):
491
526
Querier.__hosts_alive_for_testing.add(current_host)
492
527
528
+ if response.status_code == RATE_LIMIT_STATUS_CODE:
529
+ retries_left = retry_info_map[url]
530
+
531
+ if retries_left > 0:
532
+ retry_info_map[url] = retries_left - 1
533
+
534
+ attempts_made = max_retries - retries_left
535
+ delay = (10 + attempts_made * 250) / 1000
536
+
537
+ await asyncio.sleep(delay)
538
+ return await self.__send_request_helper(
539
+ path, method, http_function, no_of_tries, retry_info_map
540
+ )
541
+
493
542
if is_4xx_error(response.status_code) or is_5xx_error(response.status_code): # type: ignore
494
543
raise_general_exception(
495
544
"SuperTokens core threw an error for a "
@@ -507,13 +556,20 @@ <h2 class="section-title" id="header-classes">Classes</h2>
507
556
except JSONDecodeError:
508
557
return response.text
509
558
510
- except (ConnectionError, NetworkError, ConnectTimeout):
559
+ except (ConnectionError, NetworkError, ConnectTimeout) as _ :
511
560
return await self.__send_request_helper(
512
- path, method, http_function, no_of_tries - 1
561
+ path, method, http_function, no_of_tries - 1, retry_info_map
513
562
)
514
563
except Exception as e:
515
564
raise_general_exception(e)</ code > </ pre >
516
565
</ details >
566
+ < h3 > Class variables</ h3 >
567
+ < dl >
568
+ < dt id ="supertokens_python.querier.Querier.api_version "> < code class ="name "> var < span class ="ident "> api_version</ span > </ code > </ dt >
569
+ < dd >
570
+ < div class ="desc "> </ div >
571
+ </ dd >
572
+ </ dl >
517
573
< h3 > Static methods</ h3 >
518
574
< dl >
519
575
< dt id ="supertokens_python.querier.Querier.get_hosts_alive_for_testing "> < code class ="name flex ">
@@ -567,7 +623,7 @@ <h3>Static methods</h3>
567
623
Querier.__init_called = True
568
624
Querier.__hosts = hosts
569
625
Querier.__api_key = api_key
570
- Querier.__api_version = None
626
+ Querier.api_version = None
571
627
Querier.__last_tried_index = 0
572
628
Querier.__hosts_alive_for_testing = set()</ code > </ pre >
573
629
</ details >
@@ -603,8 +659,8 @@ <h3>Methods</h3>
603
659
< span > Expand source code</ span >
604
660
</ summary >
605
661
< pre > < code class ="python "> async def get_api_version(self):
606
- if Querier.__api_version is not None:
607
- return Querier.__api_version
662
+ if Querier.api_version is not None:
663
+ return Querier.api_version
608
664
609
665
ProcessState.get_instance().add_state(
610
666
AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -630,8 +686,8 @@ <h3>Methods</h3>
630
686
"to find the right versions"
631
687
)
632
688
633
- Querier.__api_version = api_version
634
- return Querier.__api_version </ code > </ pre >
689
+ Querier.api_version = api_version
690
+ return Querier.api_version </ code > </ pre >
635
691
</ details >
636
692
</ dd >
637
693
< dt id ="supertokens_python.querier.Querier.send_delete_request "> < code class ="name flex ">
@@ -767,6 +823,7 @@ <h2>Index</h2>
767
823
< li >
768
824
< h4 > < code > < a title ="supertokens_python.querier.Querier " href ="#supertokens_python.querier.Querier "> Querier</ a > </ code > </ h4 >
769
825
< ul class ="">
826
+ < li > < code > < a title ="supertokens_python.querier.Querier.api_version " href ="#supertokens_python.querier.Querier.api_version "> api_version</ a > </ code > </ li >
770
827
< 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 >
771
828
< 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 >
772
829
< 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