diff --git a/README.rst b/README.rst index 49d6b43..39359d5 100644 --- a/README.rst +++ b/README.rst @@ -132,11 +132,14 @@ v0.6.1 - Pool plugin now add ``blocked_by_pool`` attribute to session containing elapsed time (seconds) on pool. It allows to log this time using log plugins. -- Pool plugin now add ``blocked_by_ratelimit`` attribute to session containing elapsed time (seconds) blocked by +- RateLimit plugin now add ``blocked_by_ratelimit`` attribute to session containing elapsed time (seconds) blocked by rate limit. It allows to log this time using log plugins. - Tests improved. +- Added new exceptions: :class:`~service_client.plugins.TooManyRequestsPendingError` and + :class:`~service_client.plugins.TooMuchTimePendingError`. + - Added decorator in order to help to build service clients. It allows to define a method using a request model but to call it using keywords to build request model which will be used to call method. diff --git a/service_client/plugins.py b/service_client/plugins.py index fb87bf8..99d95ba 100644 --- a/service_client/plugins.py +++ b/service_client/plugins.py @@ -318,9 +318,20 @@ class RequestLimitError(Exception): pass +class TooManyRequestsPendingError(RequestLimitError): + pass + + +class TooMuchTimePendingError(RequestLimitError): + pass + + class BaseLimitPlugin(BasePlugin): SESSION_ATTR_TIME_BLOCKED = 'blocked' + TOO_MANY_REQ_PENDING_MSG = "Too many requests pending" + TOO_MUCH_TIME_MSG = "Request blocked too much time" + def __init__(self, limit=1, timeout=None, hard_limit=None): self.limit = limit self._counter = 0 @@ -342,7 +353,7 @@ async def _acquire(self): break if self._hard_limit is not None and self._hard_limit < self.pending: - raise RequestLimitError("Too many requests pending") + raise TooManyRequestsPendingError(self.TOO_MANY_REQ_PENDING_MSG) if self._fut is None: self._fut = self.service_client.loop.create_future() @@ -356,7 +367,7 @@ async def _acquire(self): if timeout <= 0: raise TimeoutError() except TimeoutError: - raise RequestLimitError("Request blocked too much time") + raise TooMuchTimePendingError(self.TOO_MUCH_TIME_MSG) finally: self._pending -= 1 @@ -383,6 +394,9 @@ def close(self): class Pool(BaseLimitPlugin): SESSION_ATTR_TIME_BLOCKED = 'blocked_by_pool' + TOO_MANY_REQ_PENDING_MSG = "Too many requests pending on pool" + TOO_MUCH_TIME_MSG = "Request blocked too much time on pool" + async def on_response(self, endpoint_desc, session, request_params, response): self._release() @@ -394,6 +408,9 @@ async def on_exception(self, endpoint_desc, session, request_params, ex): class RateLimit(BaseLimitPlugin): SESSION_ATTR_TIME_BLOCKED = 'blocked_by_ratelimit' + TOO_MANY_REQ_PENDING_MSG = "Too many requests pending by rate limit" + TOO_MUCH_TIME_MSG = "Request blocked too much time by rate limit" + def __init__(self, period=1, *args, **kwargs): super(RateLimit, self).__init__(*args, **kwargs) self.period = period diff --git a/service_client/utils.py b/service_client/utils.py index 0cf2af2..1566e04 100644 --- a/service_client/utils.py +++ b/service_client/utils.py @@ -53,6 +53,7 @@ def random_token(length=10): class ObjectWrapper: + def __init__(self, obj): self.__dict__['_obj'] = None self.__dict__['_data'] = {} diff --git a/tests/tests_plugins.py b/tests/tests_plugins.py index 075e802..90168b2 100644 --- a/tests/tests_plugins.py +++ b/tests/tests_plugins.py @@ -17,7 +17,7 @@ from service_client import ConnectionClosedError from service_client.plugins import PathTokens, Timeout, Headers, QueryParams, Elapsed, InnerLogger, OuterLogger, \ - TrackingToken, Pool, RequestLimitError, RateLimit + TrackingToken, Pool, RateLimit, TooMuchTimePendingError, TooManyRequestsPendingError from service_client.utils import ObjectWrapper @@ -1022,7 +1022,7 @@ async def test_timeout(self): await self.plugin.before_request(self.endpoint_desc, self.session, self.request_params) - with self.assertRaisesRegex(RequestLimitError, "Request blocked too much time"): + with self.assertRaisesRegex(TooMuchTimePendingError, "Request blocked too much time on pool"): await self.plugin.before_request(self.endpoint_desc, self.session, self.request_params) @@ -1037,7 +1037,7 @@ async def test_hard_limit(self): asyncio.ensure_future(self.plugin.before_request(self.endpoint_desc, self.session, self.request_params)) - with self.assertRaisesRegex(RequestLimitError, "Too many requests pending"): + with self.assertRaisesRegex(TooManyRequestsPendingError, "Too many requests pending on pool"): await asyncio.wait_for(self.plugin.before_request(self.endpoint_desc, self.session, self.request_params), timeout=1) @@ -1160,7 +1160,7 @@ async def test_timeout(self): await self.plugin.before_request(self.endpoint_desc, self.session, self.request_params) - with self.assertRaisesRegex(RequestLimitError, "Request blocked too much time"): + with self.assertRaisesRegex(TooMuchTimePendingError, "Request blocked too much time by rate limit"): await self.plugin.before_request(self.endpoint_desc, self.session, self.request_params) @@ -1175,7 +1175,7 @@ async def test_hard_limit(self): asyncio.ensure_future(self.plugin.before_request(self.endpoint_desc, self.session, self.request_params)) - with self.assertRaisesRegex(RequestLimitError, "Too many requests pending"): + with self.assertRaisesRegex(TooManyRequestsPendingError, "Too many requests pending by rate limit"): await asyncio.wait_for(self.plugin.before_request(self.endpoint_desc, self.session, self.request_params), timeout=1)