@@ -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
@@ -224,6 +227,7 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
224
227
method: str,
225
228
http_function: Callable[[str], Awaitable[Response]],
226
229
no_of_tries: int,
230
+ retry_info_map: Optional[Dict[str, int]] = None,
227
231
) -> Any:
228
232
if no_of_tries == 0:
229
233
raise_general_exception("No SuperTokens core available to query")
@@ -240,6 +244,14 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
240
244
Querier.__last_tried_index %= len(self.__hosts)
241
245
url = current_host + path.get_as_string_dangerous()
242
246
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
+
243
255
ProcessState.get_instance().add_state(
244
256
AllowedProcessStates.CALLING_SERVICE_IN_REQUEST_HELPER
245
257
)
@@ -249,6 +261,20 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
249
261
):
250
262
Querier.__hosts_alive_for_testing.add(current_host)
251
263
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
+
252
278
if is_4xx_error(response.status_code) or is_5xx_error(response.status_code): # type: ignore
253
279
raise_general_exception(
254
280
"SuperTokens core threw an error for a "
@@ -266,9 +292,9 @@ <h1 class="title">Module <code>supertokens_python.querier</code></h1>
266
292
except JSONDecodeError:
267
293
return response.text
268
294
269
- except (ConnectionError, NetworkError, ConnectTimeout):
295
+ except (ConnectionError, NetworkError, ConnectTimeout) as _ :
270
296
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
272
298
)
273
299
except Exception as e:
274
300
raise_general_exception(e)</ code > </ pre >
@@ -297,7 +323,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
297
323
__init_called = False
298
324
__hosts: List[Host] = []
299
325
__api_key: Union[None, str] = None
300
- __api_version = None
326
+ api_version = None
301
327
__last_tried_index: int = 0
302
328
__hosts_alive_for_testing: Set[str] = set()
303
329
@@ -324,8 +350,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
324
350
return Querier.__hosts_alive_for_testing
325
351
326
352
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
329
355
330
356
ProcessState.get_instance().add_state(
331
357
AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -351,8 +377,8 @@ <h2 class="section-title" id="header-classes">Classes</h2>
351
377
"to find the right versions"
352
378
)
353
379
354
- Querier.__api_version = api_version
355
- return Querier.__api_version
380
+ Querier.api_version = api_version
381
+ return Querier.api_version
356
382
357
383
@staticmethod
358
384
def get_instance(rid_to_core: Union[str, None] = None):
@@ -368,7 +394,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
368
394
Querier.__init_called = True
369
395
Querier.__hosts = hosts
370
396
Querier.__api_key = api_key
371
- Querier.__api_version = None
397
+ Querier.api_version = None
372
398
Querier.__last_tried_index = 0
373
399
Querier.__hosts_alive_for_testing = set()
374
400
@@ -451,6 +477,7 @@ <h2 class="section-title" id="header-classes">Classes</h2>
451
477
method: str,
452
478
http_function: Callable[[str], Awaitable[Response]],
453
479
no_of_tries: int,
480
+ retry_info_map: Optional[Dict[str, int]] = None,
454
481
) -> Any:
455
482
if no_of_tries == 0:
456
483
raise_general_exception("No SuperTokens core available to query")
@@ -467,6 +494,14 @@ <h2 class="section-title" id="header-classes">Classes</h2>
467
494
Querier.__last_tried_index %= len(self.__hosts)
468
495
url = current_host + path.get_as_string_dangerous()
469
496
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
+
470
505
ProcessState.get_instance().add_state(
471
506
AllowedProcessStates.CALLING_SERVICE_IN_REQUEST_HELPER
472
507
)
@@ -476,6 +511,20 @@ <h2 class="section-title" id="header-classes">Classes</h2>
476
511
):
477
512
Querier.__hosts_alive_for_testing.add(current_host)
478
513
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
+
479
528
if is_4xx_error(response.status_code) or is_5xx_error(response.status_code): # type: ignore
480
529
raise_general_exception(
481
530
"SuperTokens core threw an error for a "
@@ -493,13 +542,20 @@ <h2 class="section-title" id="header-classes">Classes</h2>
493
542
except JSONDecodeError:
494
543
return response.text
495
544
496
- except (ConnectionError, NetworkError, ConnectTimeout):
545
+ except (ConnectionError, NetworkError, ConnectTimeout) as _ :
497
546
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
499
548
)
500
549
except Exception as e:
501
550
raise_general_exception(e)</ code > </ pre >
502
551
</ 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 >
503
559
< h3 > Static methods</ h3 >
504
560
< dl >
505
561
< dt id ="supertokens_python.querier.Querier.get_hosts_alive_for_testing "> < code class ="name flex ">
@@ -553,7 +609,7 @@ <h3>Static methods</h3>
553
609
Querier.__init_called = True
554
610
Querier.__hosts = hosts
555
611
Querier.__api_key = api_key
556
- Querier.__api_version = None
612
+ Querier.api_version = None
557
613
Querier.__last_tried_index = 0
558
614
Querier.__hosts_alive_for_testing = set()</ code > </ pre >
559
615
</ details >
@@ -589,8 +645,8 @@ <h3>Methods</h3>
589
645
< span > Expand source code</ span >
590
646
</ summary >
591
647
< 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
594
650
595
651
ProcessState.get_instance().add_state(
596
652
AllowedProcessStates.CALLING_SERVICE_IN_GET_API_VERSION
@@ -616,8 +672,8 @@ <h3>Methods</h3>
616
672
"to find the right versions"
617
673
)
618
674
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 >
621
677
</ details >
622
678
</ dd >
623
679
< dt id ="supertokens_python.querier.Querier.send_delete_request "> < code class ="name flex ">
@@ -746,6 +802,7 @@ <h2>Index</h2>
746
802
< li >
747
803
< h4 > < code > < a title ="supertokens_python.querier.Querier " href ="#supertokens_python.querier.Querier "> Querier</ a > </ code > </ h4 >
748
804
< 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 >
749
806
< 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 >
750
807
< 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 >
751
808
< 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