)]}'
{"keystoneauth1/_fair_semaphore.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"6af42003568a1844980aa401f86f52255df37899","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    order we receive them."},{"line_number":24,"context_line":"    \"\"\""},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"    def __init__(self, concurrent\u003dNone):"},{"line_number":27,"context_line":"        self._concurrent \u003d concurrent"},{"line_number":28,"context_line":"        if concurrent:"},{"line_number":29,"context_line":"            self._count \u003d 0"}],"source_content_type":"text/x-python","patch_set":1,"id":"3f79a3b5_2b1f6609","line":26,"range":{"start_line":26,"start_character":23,"end_line":26,"end_character":33},"updated":"2018-10-16 13:05:30.000000000","message":"nit: \"concurrency\" sounds a bit more correct to me","commit_id":"95106a51080ceb1a2c0ae8908ff7e8422bdd75d2"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"24e40fd6d9e729956e40857f6566a9984e994cf0","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    order we receive them."},{"line_number":24,"context_line":"    \"\"\""},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"    def __init__(self, concurrent\u003dNone):"},{"line_number":27,"context_line":"        self._concurrent \u003d concurrent"},{"line_number":28,"context_line":"        if concurrent:"},{"line_number":29,"context_line":"            self._count \u003d 0"}],"source_content_type":"text/x-python","patch_set":1,"id":"3f79a3b5_16ffdbb1","line":26,"range":{"start_line":26,"start_character":23,"end_line":26,"end_character":33},"in_reply_to":"3f79a3b5_2b1f6609","updated":"2018-10-19 14:03:33.000000000","message":"Done","commit_id":"95106a51080ceb1a2c0ae8908ff7e8422bdd75d2"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"f5097533b654d549cd3bfc665eeee989e7fd0b39","unresolved":false,"context_lines":[{"line_number":68,"context_line":"                # We need to wait for a ticket before we can execute"},{"line_number":69,"context_line":"                ticket \u003d threading.Event()"},{"line_number":70,"context_line":"                self._queue.put(ticket)"},{"line_number":71,"context_line":"                ticket.wait()"},{"line_number":72,"context_line":"                return self._advance_timer()"},{"line_number":73,"context_line":""},{"line_number":74,"context_line":"    def _advance_timer(self):"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f79a3b5_1fd7ef52","line":71,"range":{"start_line":71,"start_character":16,"end_line":71,"end_character":29},"updated":"2018-10-19 14:24:53.000000000","message":"I don\u0027t think you should do this inside of the lock, otherwise the ticket will never be set. Or you should not set the ticket inside the lock.","commit_id":"918e811a12e57634fcbc87e857b294007fce2948"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d1fe78bb1aa0dd568f4c8b73f196b722c68d639a","unresolved":false,"context_lines":[{"line_number":43,"context_line":"    def __enter__(self):"},{"line_number":44,"context_line":"        \"\"\"Aquire a semaphore.\"\"\""},{"line_number":45,"context_line":"        # If concurrency is None, everyone is free to immediately execute"},{"line_number":46,"context_line":"        if not self._concurrency:"},{"line_number":47,"context_line":"            with self._lock:"},{"line_number":48,"context_line":"                execution_time \u003d self._advance_timer()"},{"line_number":49,"context_line":"        else:"},{"line_number":50,"context_line":"            execution_time \u003d self._get_ticket()"},{"line_number":51,"context_line":"        return self._wait_for_execution(execution_time)"}],"source_content_type":"text/x-python","patch_set":3,"id":"3f79a3b5_61da28e7","line":48,"range":{"start_line":46,"start_character":8,"end_line":48,"end_character":54},"updated":"2018-10-31 17:55:45.000000000","message":"I would add a comment here, as it\u0027s not straightforward that regardless of concurrency limits, we still adhere to the rate_delay between requests. The above comment seems to be in contradiction with the behavior here and in _wait_for_execution.\n\nPlease add a comment that rate limiting is still applied. It is worthwhile noting that this still forces a level of serialization via the mutex even if rate_limit is 0.0","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"cbe93aa2b46fda40b5333464243427eb454efa12","unresolved":false,"context_lines":[{"line_number":43,"context_line":"    def __enter__(self):"},{"line_number":44,"context_line":"        \"\"\"Aquire a semaphore.\"\"\""},{"line_number":45,"context_line":"        # If concurrency is None, everyone is free to immediately execute"},{"line_number":46,"context_line":"        if not self._concurrency:"},{"line_number":47,"context_line":"            with self._lock:"},{"line_number":48,"context_line":"                execution_time \u003d self._advance_timer()"},{"line_number":49,"context_line":"        else:"},{"line_number":50,"context_line":"            execution_time \u003d self._get_ticket()"},{"line_number":51,"context_line":"        return self._wait_for_execution(execution_time)"}],"source_content_type":"text/x-python","patch_set":3,"id":"3f79a3b5_8d4e95c1","line":48,"range":{"start_line":46,"start_character":8,"end_line":48,"end_character":54},"in_reply_to":"3f79a3b5_61da28e7","updated":"2018-10-31 20:32:06.000000000","message":"Yes! This is correct - will fix.","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":7118,"name":"Ian Wienand","email":"iwienand@redhat.com","username":"iwienand"},"change_message_id":"1b50eb896065e859bb57fd4ec224cb6e2433f526","unresolved":false,"context_lines":[{"line_number":92,"context_line":"            # If we\u0027re below the concurrency threshold, this will pop"},{"line_number":93,"context_line":"            # ourselves or one of the other executing threads that isn\u0027t"},{"line_number":94,"context_line":"            # waiting for an event."},{"line_number":95,"context_line":"            ticket \u003d self._queue.pop()"},{"line_number":96,"context_line":"            if self._queue.qsize() \u003e 0:"},{"line_number":97,"context_line":"                # If something is queued, transfer our ticket"},{"line_number":98,"context_line":"                ticket.set()"}],"source_content_type":"text/x-python","patch_set":3,"id":"3f79a3b5_41609e9e","line":95,"range":{"start_line":95,"start_character":12,"end_line":95,"end_character":38},"updated":"2018-11-09 00:10:24.000000000","message":"So queue() doens\u0027t actually have a pop() ... it\u0027s get()\n\nI don\u0027t believe the semaphore logic is quite right.  Locking being such fiendish stuff I\u0027ll push a follow-on with my thoughts and some testing...","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"6c3909b7dbf366cd53464c809b31595934f519f2","unresolved":false,"context_lines":[{"line_number":92,"context_line":"            # If we\u0027re below the concurrency threshold, this will pop"},{"line_number":93,"context_line":"            # ourselves or one of the other executing threads that isn\u0027t"},{"line_number":94,"context_line":"            # waiting for an event."},{"line_number":95,"context_line":"            ticket \u003d self._queue.pop()"},{"line_number":96,"context_line":"            if self._queue.qsize() \u003e 0:"},{"line_number":97,"context_line":"                # If something is queued, transfer our ticket"},{"line_number":98,"context_line":"                ticket.set()"}],"source_content_type":"text/x-python","patch_set":3,"id":"3f79a3b5_f9db8fe7","line":95,"range":{"start_line":95,"start_character":12,"end_line":95,"end_character":38},"in_reply_to":"3f79a3b5_41609e9e","updated":"2018-11-09 20:42:23.000000000","message":"Thanks!","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"da436b987a7899b5d34ecfdc11551c45a0188495","unresolved":false,"context_lines":[{"line_number":44,"context_line":"    def __enter__(self):"},{"line_number":45,"context_line":"        \"\"\"Aquire a semaphore.\"\"\""},{"line_number":46,"context_line":"        # If concurrency is None, everyone is free to immediately execute"},{"line_number":47,"context_line":"        if not self._concurrency:"},{"line_number":48,"context_line":"            with self._lock:"},{"line_number":49,"context_line":"                execution_time \u003d self._advance_timer()"},{"line_number":50,"context_line":"        else:"},{"line_number":51,"context_line":"            execution_time \u003d self._get_ticket()"},{"line_number":52,"context_line":"        return self._wait_for_execution(execution_time)"}],"source_content_type":"text/x-python","patch_set":4,"id":"3f79a3b5_f9f4ef57","line":49,"range":{"start_line":47,"start_character":7,"end_line":49,"end_character":54},"updated":"2018-11-09 21:04:32.000000000","message":"My comment from the previous patchset holds. I\u0027d like a note here covering that rate limiting is still applied","commit_id":"9adca1f8f6dade9b93a0557d113660e94ca61dc2"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"162797c1f59fe637188a4d2c350b94f8dc42c578","unresolved":false,"context_lines":[{"line_number":44,"context_line":"    def __enter__(self):"},{"line_number":45,"context_line":"        \"\"\"Aquire a semaphore.\"\"\""},{"line_number":46,"context_line":"        # If concurrency is None, everyone is free to immediately execute"},{"line_number":47,"context_line":"        if not self._concurrency:"},{"line_number":48,"context_line":"            with self._lock:"},{"line_number":49,"context_line":"                execution_time \u003d self._advance_timer()"},{"line_number":50,"context_line":"        else:"},{"line_number":51,"context_line":"            execution_time \u003d self._get_ticket()"},{"line_number":52,"context_line":"        return self._wait_for_execution(execution_time)"}],"source_content_type":"text/x-python","patch_set":4,"id":"3f79a3b5_777e946d","line":49,"range":{"start_line":47,"start_character":7,"end_line":49,"end_character":54},"in_reply_to":"3f79a3b5_f9f4ef57","updated":"2018-11-28 16:06:16.000000000","message":"Done","commit_id":"9adca1f8f6dade9b93a0557d113660e94ca61dc2"},{"author":{"_account_id":7102,"name":"Thomas Bechtold","email":"thomas.bechtold@chainguard.dev","username":"toabctl"},"change_message_id":"592e3471dfa1af32ee290f00583d2014e3dab1fe","unresolved":false,"context_lines":[{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    def _wait_for_execution(self, execution_time):"},{"line_number":57,"context_line":"        \"\"\"Wait until the pre-calculated time to run.\"\"\""},{"line_number":58,"context_line":"        while True:"},{"line_number":59,"context_line":"            wait_time \u003d execution_time - time.time()"},{"line_number":60,"context_line":"            if wait_time \u003c\u003d 0:"},{"line_number":61,"context_line":"                break"}],"source_content_type":"text/x-python","patch_set":6,"id":"3f79a3b5_6d56442f","line":58,"updated":"2018-12-18 10:17:44.000000000","message":"Why do you need the loop here? You can replace break with return and it should be fine.","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"383aa322229bf91c20b4442c2b47e5df830e3f6b","unresolved":false,"context_lines":[{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    def _wait_for_execution(self, execution_time):"},{"line_number":57,"context_line":"        \"\"\"Wait until the pre-calculated time to run.\"\"\""},{"line_number":58,"context_line":"        while True:"},{"line_number":59,"context_line":"            wait_time \u003d execution_time - time.time()"},{"line_number":60,"context_line":"            if wait_time \u003c\u003d 0:"},{"line_number":61,"context_line":"                break"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_0b8dde30","line":58,"in_reply_to":"3f79a3b5_6d56442f","updated":"2019-01-31 19:58:11.000000000","message":"This is a fair assessment, not worth a -1, functionally it\u0027s the same. I have gone through the logic and don\u0027t see a reason we need to calculate wait_time more than once since execution_time is a passed in value (vs. an instance attribute).\n\nThis could be cleaned up on a future patch.","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"2ffbd48f81b2957c7151e73244e2ceab335ea504","unresolved":false,"context_lines":[{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    def _wait_for_execution(self, execution_time):"},{"line_number":57,"context_line":"        \"\"\"Wait until the pre-calculated time to run.\"\"\""},{"line_number":58,"context_line":"        while True:"},{"line_number":59,"context_line":"            wait_time \u003d execution_time - time.time()"},{"line_number":60,"context_line":"            if wait_time \u003c\u003d 0:"},{"line_number":61,"context_line":"                break"}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_3f37aee5","line":58,"in_reply_to":"9fdfeff1_0b8dde30","updated":"2019-02-28 22:14:28.000000000","message":"Done","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"}],"keystoneauth1/adapter.py":[{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"6af42003568a1844980aa401f86f52255df37899","unresolved":false,"context_lines":[{"line_number":95,"context_line":"        If True, requests returning failing HTTP responses will raise an"},{"line_number":96,"context_line":"        exception; if False, the response is returned. This can be"},{"line_number":97,"context_line":"        overridden on a per-request basis via the kwarg of the same name."},{"line_number":98,"context_line":"    :param int rate:"},{"line_number":99,"context_line":"        A client-side rate limit to impose on requests expressed"},{"line_number":100,"context_line":"        in requests per second. (optional, defaults to None, which means no"},{"line_number":101,"context_line":"        rate limiting)."}],"source_content_type":"text/x-python","patch_set":1,"id":"3f79a3b5_cb37d2ae","line":98,"range":{"start_line":98,"start_character":15,"end_line":98,"end_character":20},"updated":"2018-10-16 13:05:30.000000000","message":"maybe rate_limit?\n\nalso if you use int, 1/int is either 0 or 1 on python 2 - see below","commit_id":"95106a51080ceb1a2c0ae8908ff7e8422bdd75d2"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"24e40fd6d9e729956e40857f6566a9984e994cf0","unresolved":false,"context_lines":[{"line_number":95,"context_line":"        If True, requests returning failing HTTP responses will raise an"},{"line_number":96,"context_line":"        exception; if False, the response is returned. This can be"},{"line_number":97,"context_line":"        overridden on a per-request basis via the kwarg of the same name."},{"line_number":98,"context_line":"    :param int rate:"},{"line_number":99,"context_line":"        A client-side rate limit to impose on requests expressed"},{"line_number":100,"context_line":"        in requests per second. (optional, defaults to None, which means no"},{"line_number":101,"context_line":"        rate limiting)."}],"source_content_type":"text/x-python","patch_set":1,"id":"3f79a3b5_76c08f4b","line":98,"range":{"start_line":98,"start_character":15,"end_line":98,"end_character":20},"in_reply_to":"3f79a3b5_cb37d2ae","updated":"2018-10-19 14:03:33.000000000","message":"Done","commit_id":"95106a51080ceb1a2c0ae8908ff7e8422bdd75d2"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"6af42003568a1844980aa401f86f52255df37899","unresolved":false,"context_lines":[{"line_number":163,"context_line":"        if rate:"},{"line_number":164,"context_line":"            # 1 / rate converts from requests per second to delay"},{"line_number":165,"context_line":"            # between requests needed to achieve that rate."},{"line_number":166,"context_line":"            self._rate \u003d 1 / rate"},{"line_number":167,"context_line":""},{"line_number":168,"context_line":"    def _set_endpoint_filter_kwargs(self, kwargs):"},{"line_number":169,"context_line":"        if self.service_type:"}],"source_content_type":"text/x-python","patch_set":1,"id":"3f79a3b5_0b494a2d","line":166,"range":{"start_line":166,"start_character":25,"end_line":166,"end_character":26},"updated":"2018-10-16 13:05:30.000000000","message":"let\u0027s use 1.0 to be python2-safe?","commit_id":"95106a51080ceb1a2c0ae8908ff7e8422bdd75d2"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"24e40fd6d9e729956e40857f6566a9984e994cf0","unresolved":false,"context_lines":[{"line_number":163,"context_line":"        if rate:"},{"line_number":164,"context_line":"            # 1 / rate converts from requests per second to delay"},{"line_number":165,"context_line":"            # between requests needed to achieve that rate."},{"line_number":166,"context_line":"            self._rate \u003d 1 / rate"},{"line_number":167,"context_line":""},{"line_number":168,"context_line":"    def _set_endpoint_filter_kwargs(self, kwargs):"},{"line_number":169,"context_line":"        if self.service_type:"}],"source_content_type":"text/x-python","patch_set":1,"id":"3f79a3b5_96c9ab7b","line":166,"range":{"start_line":166,"start_character":25,"end_line":166,"end_character":26},"in_reply_to":"3f79a3b5_0b494a2d","updated":"2018-10-19 14:03:33.000000000","message":"Done","commit_id":"95106a51080ceb1a2c0ae8908ff7e8422bdd75d2"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"6af42003568a1844980aa401f86f52255df37899","unresolved":false,"context_lines":[{"line_number":234,"context_line":"        with self._rate_semaphore:"},{"line_number":235,"context_line":"            if self._rate:"},{"line_number":236,"context_line":"                self._block_until_ready()"},{"line_number":237,"context_line":"                self._rate_time \u003d time.time()"},{"line_number":238,"context_line":""},{"line_number":239,"context_line":"        return self.session.request(url, method, **kwargs)"},{"line_number":240,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"3f79a3b5_4bf182dd","line":237,"range":{"start_line":237,"start_character":16,"end_line":237,"end_character":31},"updated":"2018-10-16 13:05:30.000000000","message":"this looks unused, did you mean rate_last_ts?","commit_id":"95106a51080ceb1a2c0ae8908ff7e8422bdd75d2"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"24e40fd6d9e729956e40857f6566a9984e994cf0","unresolved":false,"context_lines":[{"line_number":234,"context_line":"        with self._rate_semaphore:"},{"line_number":235,"context_line":"            if self._rate:"},{"line_number":236,"context_line":"                self._block_until_ready()"},{"line_number":237,"context_line":"                self._rate_time \u003d time.time()"},{"line_number":238,"context_line":""},{"line_number":239,"context_line":"        return self.session.request(url, method, **kwargs)"},{"line_number":240,"context_line":""}],"source_content_type":"text/x-python","patch_set":1,"id":"3f79a3b5_b68b8720","line":237,"range":{"start_line":237,"start_character":16,"end_line":237,"end_character":31},"in_reply_to":"3f79a3b5_4bf182dd","updated":"2018-10-19 14:03:33.000000000","message":"Yup!","commit_id":"95106a51080ceb1a2c0ae8908ff7e8422bdd75d2"},{"author":{"_account_id":10239,"name":"Dmitry Tantsur","email":"dtantsur@protonmail.com","username":"dtantsur"},"change_message_id":"6af42003568a1844980aa401f86f52255df37899","unresolved":false,"context_lines":[{"line_number":244,"context_line":"                delta \u003d time.time() - self._rate_last_ts"},{"line_number":245,"context_line":"                if delta \u003e\u003d self._rate:"},{"line_number":246,"context_line":"                    break"},{"line_number":247,"context_line":"                time.sleep(self._rate - delta)"},{"line_number":248,"context_line":"            self._rate_last_ts \u003d time.time()"},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"    def get_token(self, auth\u003dNone):"}],"source_content_type":"text/x-python","patch_set":1,"id":"3f79a3b5_cb8a7218","line":247,"range":{"start_line":247,"start_character":0,"end_line":247,"end_character":46},"updated":"2018-10-16 13:05:30.000000000","message":"it seems that using sleep inside of lock will force concurrency\u003d\u003d1, no? only one process will enter block_until_ready.\n\noverall, I wonder if we can hide this logic completely within your semaphore implementation, so that we can simply do:\n\n with self._rate_semaphore\n     return self.session.request(url, method, **kwargs)","commit_id":"95106a51080ceb1a2c0ae8908ff7e8422bdd75d2"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"24e40fd6d9e729956e40857f6566a9984e994cf0","unresolved":false,"context_lines":[{"line_number":244,"context_line":"                delta \u003d time.time() - self._rate_last_ts"},{"line_number":245,"context_line":"                if delta \u003e\u003d self._rate:"},{"line_number":246,"context_line":"                    break"},{"line_number":247,"context_line":"                time.sleep(self._rate - delta)"},{"line_number":248,"context_line":"            self._rate_last_ts \u003d time.time()"},{"line_number":249,"context_line":""},{"line_number":250,"context_line":"    def get_token(self, auth\u003dNone):"}],"source_content_type":"text/x-python","patch_set":1,"id":"3f79a3b5_9c254d19","line":247,"range":{"start_line":247,"start_character":0,"end_line":247,"end_character":46},"in_reply_to":"3f79a3b5_cb8a7218","updated":"2018-10-19 14:03:33.000000000","message":"Yes - I think that\u0027s a great idea -- new impl coming.","commit_id":"95106a51080ceb1a2c0ae8908ff7e8422bdd75d2"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d1fe78bb1aa0dd568f4c8b73f196b722c68d639a","unresolved":false,"context_lines":[{"line_number":95,"context_line":"        overridden on a per-request basis via the kwarg of the same name."},{"line_number":96,"context_line":"    :param float rate_limit:"},{"line_number":97,"context_line":"        A client-side rate limit to impose on requests expressed"},{"line_number":98,"context_line":"        in requests per second. (optional, defaults to None, which means no"},{"line_number":99,"context_line":"        rate limiting)."},{"line_number":100,"context_line":"    :param int concurrency:"},{"line_number":101,"context_line":"        How many simultaneous http requests this Adapter can be used for."}],"source_content_type":"text/x-python","patch_set":3,"id":"3f79a3b5_01249419","line":98,"range":{"start_line":98,"start_character":54,"end_line":98,"end_character":59},"updated":"2018-10-31 17:55:45.000000000","message":"NIT: It defaults to 0.0 meaning no rate limit.","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"cbe93aa2b46fda40b5333464243427eb454efa12","unresolved":false,"context_lines":[{"line_number":95,"context_line":"        overridden on a per-request basis via the kwarg of the same name."},{"line_number":96,"context_line":"    :param float rate_limit:"},{"line_number":97,"context_line":"        A client-side rate limit to impose on requests expressed"},{"line_number":98,"context_line":"        in requests per second. (optional, defaults to None, which means no"},{"line_number":99,"context_line":"        rate limiting)."},{"line_number":100,"context_line":"    :param int concurrency:"},{"line_number":101,"context_line":"        How many simultaneous http requests this Adapter can be used for."}],"source_content_type":"text/x-python","patch_set":3,"id":"3f79a3b5_0dc045f9","line":98,"range":{"start_line":98,"start_character":54,"end_line":98,"end_character":59},"in_reply_to":"3f79a3b5_01249419","updated":"2018-10-31 20:32:06.000000000","message":"Done","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d1fe78bb1aa0dd568f4c8b73f196b722c68d639a","unresolved":false,"context_lines":[{"line_number":160,"context_line":"            # between requests needed to achieve that rate."},{"line_number":161,"context_line":"            rate_delay \u003d 1.0 / rate_limit"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"        self._rate_semaphore \u003d _fair_semaphore.FairSemaphore("},{"line_number":164,"context_line":"            concurrency, rate_delay)"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"    def _set_endpoint_filter_kwargs(self, kwargs):"}],"source_content_type":"text/x-python","patch_set":3,"id":"3f79a3b5_2112f0b4","line":163,"updated":"2018-10-31 17:55:45.000000000","message":"Is it expected that it is impossible in the adapter to use a non-rate semaphore?","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"cbe93aa2b46fda40b5333464243427eb454efa12","unresolved":false,"context_lines":[{"line_number":160,"context_line":"            # between requests needed to achieve that rate."},{"line_number":161,"context_line":"            rate_delay \u003d 1.0 / rate_limit"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"        self._rate_semaphore \u003d _fair_semaphore.FairSemaphore("},{"line_number":164,"context_line":"            concurrency, rate_delay)"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"    def _set_endpoint_filter_kwargs(self, kwargs):"}],"source_content_type":"text/x-python","patch_set":3,"id":"3f79a3b5_cdc9ed24","line":163,"in_reply_to":"3f79a3b5_2112f0b4","updated":"2018-10-31 20:32:06.000000000","message":"I don\u0027t know? Probably - should we just call it self._semaphore ?","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"f3690899aa4ee787700ce794d1e36f4c29e041b5","unresolved":false,"context_lines":[{"line_number":160,"context_line":"            # between requests needed to achieve that rate."},{"line_number":161,"context_line":"            rate_delay \u003d 1.0 / rate_limit"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"        self._rate_semaphore \u003d _fair_semaphore.FairSemaphore("},{"line_number":164,"context_line":"            concurrency, rate_delay)"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"    def _set_endpoint_filter_kwargs(self, kwargs):"}],"source_content_type":"text/x-python","patch_set":3,"id":"3f79a3b5_df999080","line":163,"in_reply_to":"3f79a3b5_cdc9ed24","updated":"2018-10-31 21:05:21.000000000","message":"++ no need to change just checking if this is as intended. self._semaphore would be better but *shrug* It\u0027s not hard to tell the intention. The key to the question was that the adapter forces use of FairSemaphore rather than optionally NullOp one.","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"92c3bb276c99e711c7f06018cb22231b6b16908e","unresolved":false,"context_lines":[{"line_number":160,"context_line":"            # between requests needed to achieve that rate."},{"line_number":161,"context_line":"            rate_delay \u003d 1.0 / rate_limit"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"        self._rate_semaphore \u003d _fair_semaphore.FairSemaphore("},{"line_number":164,"context_line":"            concurrency, rate_delay)"},{"line_number":165,"context_line":""},{"line_number":166,"context_line":"    def _set_endpoint_filter_kwargs(self, kwargs):"}],"source_content_type":"text/x-python","patch_set":3,"id":"3f79a3b5_2ed63128","line":163,"in_reply_to":"3f79a3b5_df999080","updated":"2018-11-02 14:33:25.000000000","message":"Yes - although if rate_limit and concurrency are not set - the FairSemaphore should be effectively passthrough.","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":7102,"name":"Thomas Bechtold","email":"thomas.bechtold@chainguard.dev","username":"toabctl"},"change_message_id":"592e3471dfa1af32ee290f00583d2014e3dab1fe","unresolved":false,"context_lines":[{"line_number":93,"context_line":"        If True, requests returning failing HTTP responses will raise an"},{"line_number":94,"context_line":"        exception; if False, the response is returned. This can be"},{"line_number":95,"context_line":"        overridden on a per-request basis via the kwarg of the same name."},{"line_number":96,"context_line":"    :param float rate_limit:"},{"line_number":97,"context_line":"        A client-side rate limit to impose on requests expressed"},{"line_number":98,"context_line":"        in requests per second. (optional, defaults to None, which means no"},{"line_number":99,"context_line":"        rate limiting)."}],"source_content_type":"text/x-python","patch_set":6,"id":"3f79a3b5_6832b2f6","line":96,"updated":"2018-12-18 10:17:44.000000000","message":"Why float? Can you have 1/2 requests per second?","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"383aa322229bf91c20b4442c2b47e5df830e3f6b","unresolved":false,"context_lines":[{"line_number":93,"context_line":"        If True, requests returning failing HTTP responses will raise an"},{"line_number":94,"context_line":"        exception; if False, the response is returned. This can be"},{"line_number":95,"context_line":"        overridden on a per-request basis via the kwarg of the same name."},{"line_number":96,"context_line":"    :param float rate_limit:"},{"line_number":97,"context_line":"        A client-side rate limit to impose on requests expressed"},{"line_number":98,"context_line":"        in requests per second. (optional, defaults to None, which means no"},{"line_number":99,"context_line":"        rate limiting)."}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_ebb73af4","line":96,"in_reply_to":"3f79a3b5_6832b2f6","updated":"2019-01-31 19:58:11.000000000","message":"This allows for 1 request every 2 seconds (.5 requests per second). This is an edge case, but generally useful to support out of the box.","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"a737b53cbd90a3d161ebf0dff1f134c98eda59d2","unresolved":false,"context_lines":[{"line_number":93,"context_line":"        If True, requests returning failing HTTP responses will raise an"},{"line_number":94,"context_line":"        exception; if False, the response is returned. This can be"},{"line_number":95,"context_line":"        overridden on a per-request basis via the kwarg of the same name."},{"line_number":96,"context_line":"    :param float rate_limit:"},{"line_number":97,"context_line":"        A client-side rate limit to impose on requests expressed"},{"line_number":98,"context_line":"        in requests per second. (optional, defaults to None, which means no"},{"line_number":99,"context_line":"        rate limiting)."}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_1cbd1db0","line":96,"in_reply_to":"9fdfeff1_ebb73af4","updated":"2019-02-28 17:52:09.000000000","message":"And in fact - we have had to set such rates before in infra land.","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"02ba5238265b7d64190855c13a7ca3ec58f25fe5","unresolved":false,"context_lines":[{"line_number":115,"context_line":"                 min_version\u003dNone, max_version\u003dNone,"},{"line_number":116,"context_line":"                 default_microversion\u003dNone, status_code_retries\u003dNone,"},{"line_number":117,"context_line":"                 retriable_status_codes\u003dNone, raise_exc\u003dNone,"},{"line_number":118,"context_line":"                 rate_limit\u003d0.0, concurrency\u003dNone,"},{"line_number":119,"context_line":"                 ):"},{"line_number":120,"context_line":"        if version and (min_version or max_version):"},{"line_number":121,"context_line":"            raise TypeError("}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_edc185e5","line":118,"range":{"start_line":118,"start_character":17,"end_line":118,"end_character":27},"updated":"2019-02-28 20:29:54.000000000","message":"I don\u0027t know if this is a me thing, but it took me a while to figure out if I was supposed to invoke the semaphore through this or the session? Also, the conversion was a bit weird to grok, but that could be because we don\u0027t have any documentation.","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"},{"author":{"_account_id":7102,"name":"Thomas Bechtold","email":"thomas.bechtold@chainguard.dev","username":"toabctl"},"change_message_id":"592e3471dfa1af32ee290f00583d2014e3dab1fe","unresolved":false,"context_lines":[{"line_number":115,"context_line":"                 min_version\u003dNone, max_version\u003dNone,"},{"line_number":116,"context_line":"                 default_microversion\u003dNone, status_code_retries\u003dNone,"},{"line_number":117,"context_line":"                 retriable_status_codes\u003dNone, raise_exc\u003dNone,"},{"line_number":118,"context_line":"                 rate_limit\u003d0.0, concurrency\u003dNone,"},{"line_number":119,"context_line":"                 ):"},{"line_number":120,"context_line":"        if version and (min_version or max_version):"},{"line_number":121,"context_line":"            raise TypeError("}],"source_content_type":"text/x-python","patch_set":6,"id":"3f79a3b5_08f9be19","line":118,"updated":"2018-12-18 10:17:44.000000000","message":"class doc says the default for rate_limit is None (but it\u0027s 0.0 here)","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"383aa322229bf91c20b4442c2b47e5df830e3f6b","unresolved":false,"context_lines":[{"line_number":115,"context_line":"                 min_version\u003dNone, max_version\u003dNone,"},{"line_number":116,"context_line":"                 default_microversion\u003dNone, status_code_retries\u003dNone,"},{"line_number":117,"context_line":"                 retriable_status_codes\u003dNone, raise_exc\u003dNone,"},{"line_number":118,"context_line":"                 rate_limit\u003d0.0, concurrency\u003dNone,"},{"line_number":119,"context_line":"                 ):"},{"line_number":120,"context_line":"        if version and (min_version or max_version):"},{"line_number":121,"context_line":"            raise TypeError("}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_fe94db38","line":118,"in_reply_to":"3f79a3b5_08f9be19","updated":"2019-01-31 19:58:11.000000000","message":"Minor difference that came out with the implementation. This could be fixed in the docstring or in the code with an:\n\n  if rate_limit is None:\n      rate_limit \u003d 0.0","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"2ffbd48f81b2957c7151e73244e2ceab335ea504","unresolved":false,"context_lines":[{"line_number":115,"context_line":"                 min_version\u003dNone, max_version\u003dNone,"},{"line_number":116,"context_line":"                 default_microversion\u003dNone, status_code_retries\u003dNone,"},{"line_number":117,"context_line":"                 retriable_status_codes\u003dNone, raise_exc\u003dNone,"},{"line_number":118,"context_line":"                 rate_limit\u003d0.0, concurrency\u003dNone,"},{"line_number":119,"context_line":"                 ):"},{"line_number":120,"context_line":"        if version and (min_version or max_version):"},{"line_number":121,"context_line":"            raise TypeError("}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_1c0e783a","line":118,"range":{"start_line":118,"start_character":17,"end_line":118,"end_character":27},"in_reply_to":"9fdfeff1_ad45bd70","updated":"2019-02-28 22:14:28.000000000","message":"Done","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"319a94c4ba66fd22499b54daa1df06a6e60288b1","unresolved":false,"context_lines":[{"line_number":115,"context_line":"                 min_version\u003dNone, max_version\u003dNone,"},{"line_number":116,"context_line":"                 default_microversion\u003dNone, status_code_retries\u003dNone,"},{"line_number":117,"context_line":"                 retriable_status_codes\u003dNone, raise_exc\u003dNone,"},{"line_number":118,"context_line":"                 rate_limit\u003d0.0, concurrency\u003dNone,"},{"line_number":119,"context_line":"                 ):"},{"line_number":120,"context_line":"        if version and (min_version or max_version):"},{"line_number":121,"context_line":"            raise TypeError("}],"source_content_type":"text/x-python","patch_set":6,"id":"9fdfeff1_ad45bd70","line":118,"range":{"start_line":118,"start_character":17,"end_line":118,"end_character":27},"in_reply_to":"9fdfeff1_edc185e5","updated":"2019-02-28 20:33:29.000000000","message":"Fair that this needs expanded documentation. I can totally add that in a followup. Beyond docs (if you dont mind +2/+A otherwise) think this can land and release ASAP for the S cycle?","commit_id":"dcbe8dd0aa01ea6a671d69f96dff704f1036ee4c"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"7ecc4c57caf30c1ed4c8a400ef79a4ad8603d0f6","unresolved":false,"context_lines":[{"line_number":94,"context_line":"        exception; if False, the response is returned. This can be"},{"line_number":95,"context_line":"        overridden on a per-request basis via the kwarg of the same name."},{"line_number":96,"context_line":"    :param float rate_limit:"},{"line_number":97,"context_line":"        A client-side rate limit to impose on requests made through this"},{"line_number":98,"context_line":"        adapter in requests per second. For instance, a rate_limit of 2"},{"line_number":99,"context_line":"        means to allow no more than 2 requests per second, and a rate_limit"},{"line_number":100,"context_line":"        of 0.5 means to allow no more than 1 request every two seconds."},{"line_number":101,"context_line":"        (optional, defaults to None, which means no rate limiting will be"},{"line_number":102,"context_line":"        applied)."},{"line_number":103,"context_line":"    :param int concurrency:"},{"line_number":104,"context_line":"        How many simultaneous http requests this Adapter can be used for."},{"line_number":105,"context_line":"        (optional, defaults to None, which means no limit)."}],"source_content_type":"text/x-python","patch_set":7,"id":"9fdfeff1_1f6aeab1","line":102,"range":{"start_line":97,"start_character":8,"end_line":102,"end_character":17},"updated":"2019-02-28 22:17:46.000000000","message":"Thanks for the clarity here.","commit_id":"09934718f7d34d61abcb63b07d6e5c1d783d4150"}],"keystoneauth1/tests/unit/test_fair_sempahore.py":[{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"da436b987a7899b5d34ecfdc11551c45a0188495","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    def _thread_worker(self):"},{"line_number":25,"context_line":"        while True:"},{"line_number":26,"context_line":"            # note really"},{"line_number":27,"context_line":"            #  item \u003d self.q.get()"},{"line_number":28,"context_line":"            # but we don\u0027t care about the value"},{"line_number":29,"context_line":"            self.q.get()"},{"line_number":30,"context_line":"            with self.s:"},{"line_number":31,"context_line":"                pass"}],"source_content_type":"text/x-python","patch_set":4,"id":"3f79a3b5_d9181384","line":28,"range":{"start_line":26,"start_character":0,"end_line":28,"end_character":47},"updated":"2018-11-09 21:04:32.000000000","message":"This is somewhat painful to grok. Can be fixed later, but lets make comments clear.","commit_id":"9adca1f8f6dade9b93a0557d113660e94ca61dc2"},{"author":{"_account_id":2,"name":"Monty Taylor","email":"mordred@inaugust.com","username":"mordred"},"change_message_id":"162797c1f59fe637188a4d2c350b94f8dc42c578","unresolved":false,"context_lines":[{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    def _thread_worker(self):"},{"line_number":25,"context_line":"        while True:"},{"line_number":26,"context_line":"            # note really"},{"line_number":27,"context_line":"            #  item \u003d self.q.get()"},{"line_number":28,"context_line":"            # but we don\u0027t care about the value"},{"line_number":29,"context_line":"            self.q.get()"},{"line_number":30,"context_line":"            with self.s:"},{"line_number":31,"context_line":"                pass"}],"source_content_type":"text/x-python","patch_set":4,"id":"3f79a3b5_57ecb825","line":28,"range":{"start_line":26,"start_character":0,"end_line":28,"end_character":47},"in_reply_to":"3f79a3b5_d9181384","updated":"2018-11-28 16:06:16.000000000","message":"Done","commit_id":"9adca1f8f6dade9b93a0557d113660e94ca61dc2"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"da436b987a7899b5d34ecfdc11551c45a0188495","unresolved":false,"context_lines":[{"line_number":49,"context_line":""},{"line_number":50,"context_line":"    # We should be waiting at least 0.1s between operations, so"},{"line_number":51,"context_line":"    # the 10 operations must take at *least* 1 second"},{"line_number":52,"context_line":"    def test_semaphore_no_concurrency(self):"},{"line_number":53,"context_line":"        start \u003d timer()"},{"line_number":54,"context_line":"        self._concurrency_core(None, 0.1)"},{"line_number":55,"context_line":"        end \u003d timer()"},{"line_number":56,"context_line":"        self.assertTrue((end - start) \u003e 1.0)"},{"line_number":57,"context_line":""},{"line_number":58,"context_line":"    def test_semaphore_single_concurrency(self):"},{"line_number":59,"context_line":"        start \u003d timer()"}],"source_content_type":"text/x-python","patch_set":4,"id":"3f79a3b5_042dc28e","line":56,"range":{"start_line":52,"start_character":0,"end_line":56,"end_character":44},"updated":"2018-11-09 21:04:32.000000000","message":"We could also freeze the clock and manually step the ticks forward, iirc freezegun can handle sleep and stepping ticks forward now. This works for the moment. \n\nI would also like to see a MockCall that checks that not only this took the expected time but the expected number of calls were made. I get this is mostly testing python, but it is somewhat relevant for our case since we have implemented a rate-limiter/concurency limiter. We should ensure we are making the correct number of calls not just that 8 of the 10 calls took more time by accident. This applies to the other tests as well.","commit_id":"9adca1f8f6dade9b93a0557d113660e94ca61dc2"}],"releasenotes/notes/client-side-rate-limiting-dec43fc9b54f5b70.yaml":[{"author":{"_account_id":1,"name":"James E. Blair","email":"jim@acmegating.com","username":"corvus"},"change_message_id":"6ecf5fc675247109a2cb797b808a7ab2a8a8c2a1","unresolved":false,"context_lines":[{"line_number":6,"context_line":"    maximum rate at which to execute requests. ``parallel_limit`` allows"},{"line_number":7,"context_line":"    for the creation of a semaphore to control the maximum number of"},{"line_number":8,"context_line":"    requests that can be active at any one given point in time."},{"line_number":9,"context_line":"    Both default to ``None`` which has the normal behavior or not limiting"},{"line_number":10,"context_line":"    requests in any manner."}],"source_content_type":"text/x-yaml","patch_set":3,"id":"3f79a3b5_1a9a7912","line":9,"updated":"2018-10-22 16:49:24.000000000","message":"s/or not/of not/","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"},{"author":{"_account_id":2903,"name":"Morgan Fainberg","email":"morgan.fainberg@gmail.com","username":"mdrnstm"},"change_message_id":"d1fe78bb1aa0dd568f4c8b73f196b722c68d639a","unresolved":false,"context_lines":[{"line_number":6,"context_line":"    maximum rate at which to execute requests. ``parallel_limit`` allows"},{"line_number":7,"context_line":"    for the creation of a semaphore to control the maximum number of"},{"line_number":8,"context_line":"    requests that can be active at any one given point in time."},{"line_number":9,"context_line":"    Both default to ``None`` which has the normal behavior or not limiting"},{"line_number":10,"context_line":"    requests in any manner."}],"source_content_type":"text/x-yaml","patch_set":3,"id":"3f79a3b5_8cc45b44","line":9,"in_reply_to":"3f79a3b5_1a9a7912","updated":"2018-10-31 17:55:45.000000000","message":"++","commit_id":"791a3fb8d9963e562d8b9f6386d4d11437a21d2b"}]}
