@@ -13,8 +13,8 @@ class RateLimiter(object):
1313
1414 __slots__ = (
1515 "_lock" ,
16- "current_window " ,
17- "last_update " ,
16+ "current_window_ns " ,
17+ "last_update_ns " ,
1818 "max_tokens" ,
1919 "prev_window_rate" ,
2020 "rate_limit" ,
@@ -38,54 +38,54 @@ def __init__(self, rate_limit):
3838 self .tokens = rate_limit # type: float
3939 self .max_tokens = rate_limit
4040
41- self .last_update = compat .monotonic ()
41+ self .last_update_ns = compat .monotonic_ns ()
4242
43- self .current_window = 0 # type: float
43+ self .current_window_ns = 0 # type: float
4444 self .tokens_allowed = 0
4545 self .tokens_total = 0
4646 self .prev_window_rate = None # type: Optional[float]
4747
4848 self ._lock = threading .Lock ()
4949
50- def is_allowed (self ):
51- # type: () -> bool
50+ def is_allowed (self , timestamp_ns ):
51+ # type: (int ) -> bool
5252 """
5353 Check whether the current request is allowed or not
5454
5555 This method will also reduce the number of available tokens by 1
5656
57+ :param int timestamp_ns: timestamp in nanoseconds for the current request.
5758 :returns: Whether the current request is allowed or not
5859 :rtype: :obj:`bool`
5960 """
6061 # Determine if it is allowed
61- allowed = self ._is_allowed ()
62+ allowed = self ._is_allowed (timestamp_ns )
6263 # Update counts used to determine effective rate
63- self ._update_rate_counts (allowed )
64+ self ._update_rate_counts (allowed , timestamp_ns )
6465 return allowed
6566
66- def _update_rate_counts (self , allowed ):
67- # type: (bool) -> None
68- now = compat .monotonic ()
69-
67+ def _update_rate_counts (self , allowed , timestamp_ns ):
68+ # type: (bool, int) -> None
7069 # No tokens have been seen yet, start a new window
71- if not self .current_window :
72- self .current_window = now
70+ if not self .current_window_ns :
71+ self .current_window_ns = timestamp_ns
7372
7473 # If more than 1 second has past since last window, reset
75- elif now - self .current_window >= 1.0 :
74+ # DEV: We are comparing nanoseconds, so 1e9 is 1 second
75+ elif timestamp_ns - self .current_window_ns >= 1e9 :
7676 # Store previous window's rate to average with current for `.effective_rate`
7777 self .prev_window_rate = self ._current_window_rate ()
7878 self .tokens_allowed = 0
7979 self .tokens_total = 0
80- self .current_window = now
80+ self .current_window_ns = timestamp_ns
8181
8282 # Keep track of total tokens seen vs allowed
8383 if allowed :
8484 self .tokens_allowed += 1
8585 self .tokens_total += 1
8686
87- def _is_allowed (self ):
88- # type: () -> bool
87+ def _is_allowed (self , timestamp_ns ):
88+ # type: (int ) -> bool
8989 # Rate limit of 0 blocks everything
9090 if self .rate_limit == 0 :
9191 return False
@@ -96,24 +96,24 @@ def _is_allowed(self):
9696
9797 # Lock, we need this to be thread safe, it should be shared by all threads
9898 with self ._lock :
99- self ._replenish ()
99+ self ._replenish (timestamp_ns )
100100
101101 if self .tokens >= 1 :
102102 self .tokens -= 1
103103 return True
104104
105105 return False
106106
107- def _replenish (self ):
108- # type: () -> None
107+ def _replenish (self , timestamp_ns ):
108+ # type: (int ) -> None
109109 # If we are at the max, we do not need to add any more
110110 if self .tokens == self .max_tokens :
111111 return
112112
113113 # Add more available tokens based on how much time has passed
114- now = compat . monotonic ()
115- elapsed = now - self .last_update
116- self .last_update = now
114+ # DEV: We store as nanoseconds, convert to seconds
115+ elapsed = ( timestamp_ns - self .last_update_ns ) / 1e9
116+ self .last_update_ns = timestamp_ns
117117
118118 # Update the number of available tokens, but ensure we do not exceed the max
119119 self .tokens = min (
@@ -147,11 +147,11 @@ def effective_rate(self):
147147 return (self ._current_window_rate () + self .prev_window_rate ) / 2.0
148148
149149 def __repr__ (self ):
150- return "{}(rate_limit={!r}, tokens={!r}, last_update ={!r}, effective_rate={!r})" .format (
150+ return "{}(rate_limit={!r}, tokens={!r}, last_update_ns ={!r}, effective_rate={!r})" .format (
151151 self .__class__ .__name__ ,
152152 self .rate_limit ,
153153 self .tokens ,
154- self .last_update ,
154+ self .last_update_ns ,
155155 self .effective_rate ,
156156 )
157157
0 commit comments