)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"5a1ca12ec97f9f19333be7a794f24adbea7ab2fb","unresolved":false,"context_lines":[{"line_number":13,"context_line":"in retry. The value in \"Retry-After\" header will be in seconds"},{"line_number":14,"context_line":"or GMT value, client should handle both the cases."},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"How many times client should retry will be controlled by user"},{"line_number":17,"context_line":"through \"--retries\" argument to nova api example,"},{"line_number":18,"context_line":"$ nova --retries 3 availability-zone-list"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"If request was not sucessful within the retries, client should"},{"line_number":21,"context_line":"raise the exception."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"1a1ced50_1ff0c9c8","line":18,"range":{"start_line":16,"start_character":0,"end_line":18,"end_character":41},"updated":"2017-03-21 14:51:23.000000000","message":"I don\u0027t see --retries added anywhere, and it doesn\u0027t currently exist in novaclient that I can see.","commit_id":"204f7243ca74bdbadc037ab7742b2eeed3811f7e"}],"novaclient/client.py":[{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"d7330459d2221e07c127945f6c14469c4a182efd","unresolved":false,"context_lines":[{"line_number":94,"context_line":"                        raise"},{"line_number":95,"context_line":"                    msg \u003d \"Retrying after %s seconds.\" % ratelim.retry_after"},{"line_number":96,"context_line":"                    self._logger.debug(msg)"},{"line_number":97,"context_line":"                    sleep(ratelim.retry_after)"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"        # TODO(andreykurilin): uncomment this line, when we will be able to"},{"line_number":100,"context_line":"        #   check only nova-related calls"}],"source_content_type":"text/x-python","patch_set":23,"id":"bf3e73b7_7babefd5","line":97,"updated":"2017-08-07 15:13:52.000000000","message":"I think we should put an upper limit on the amount of time we\u0027re willing to sleep.  All it would take would be a local time being off by, say, 60 minutes, and you could have the client sleeping for 3660 seconds!  (Or -3540 seconds, but that at least would be caught by the \"ratelim.retry_after \u003c 1\" clause ;)","commit_id":"1567ccccc2ad2e1d3d840b34dbaf6aaa2f4e0c6c"},{"author":{"_account_id":22056,"name":"yushangbin","email":"shangbin.yu@easystack.cn","username":"yushangbin"},"change_message_id":"5e047125844988a448efe5eb22ef7cf828d5076c","unresolved":false,"context_lines":[{"line_number":94,"context_line":"                        raise"},{"line_number":95,"context_line":"                    msg \u003d \"Retrying after %s seconds.\" % ratelim.retry_after"},{"line_number":96,"context_line":"                    self._logger.debug(msg)"},{"line_number":97,"context_line":"                    sleep(ratelim.retry_after)"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"        # TODO(andreykurilin): uncomment this line, when we will be able to"},{"line_number":100,"context_line":"        #   check only nova-related calls"}],"source_content_type":"text/x-python","patch_set":23,"id":"9f436f4f_f66ca49d","line":97,"in_reply_to":"bf3e73b7_7babefd5","updated":"2017-08-08 17:10:17.000000000","message":"Hmm, it\u0027s reasonable, but the value of upper limit should be considered, I would just set it to be 30 seconds.","commit_id":"1567ccccc2ad2e1d3d840b34dbaf6aaa2f4e0c6c"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"ed4a3d004030dec383fd62c211ba9bfe2eaae5c8","unresolved":false,"context_lines":[{"line_number":94,"context_line":"                        raise"},{"line_number":95,"context_line":"                    if ratelim.retry_after \u003e 30:"},{"line_number":96,"context_line":"                        msg \u003d \"Sleeping time is longer than 30 seconds!\""},{"line_number":97,"context_line":"                        self._logger.error(msg)"},{"line_number":98,"context_line":"                        raise"},{"line_number":99,"context_line":"                    msg \u003d \"Retrying after %s seconds.\" % ratelim.retry_after"},{"line_number":100,"context_line":"                    self._logger.debug(msg)"}],"source_content_type":"text/x-python","patch_set":24,"id":"9f436f4f_b23de8bc","line":97,"updated":"2017-08-09 15:30:29.000000000","message":"Make it a warning and update the message to indicate we\u0027re not going to sleep; e.g., maybe something like:\n\n    \"Sleep time of %d seconds is greater than threshold of 30; retry command after %d seconds\"\n\nFor extra points, perhaps the threshold could be a function or constructor argument defaulting to 30 seconds?","commit_id":"0a93ee61099be5bba328da148ddf6528d8241c13"},{"author":{"_account_id":22056,"name":"yushangbin","email":"shangbin.yu@easystack.cn","username":"yushangbin"},"change_message_id":"2368f79484885af6d26d0bccbac73934317bf6a3","unresolved":false,"context_lines":[{"line_number":94,"context_line":"                        raise"},{"line_number":95,"context_line":"                    if ratelim.retry_after \u003e 30:"},{"line_number":96,"context_line":"                        msg \u003d \"Sleeping time is longer than 30 seconds!\""},{"line_number":97,"context_line":"                        self._logger.error(msg)"},{"line_number":98,"context_line":"                        raise"},{"line_number":99,"context_line":"                    msg \u003d \"Retrying after %s seconds.\" % ratelim.retry_after"},{"line_number":100,"context_line":"                    self._logger.debug(msg)"}],"source_content_type":"text/x-python","patch_set":24,"id":"9f436f4f_d02e1542","line":97,"in_reply_to":"9f436f4f_b23de8bc","updated":"2017-08-10 04:54:43.000000000","message":"Thanks for your advice, Kevin.","commit_id":"0a93ee61099be5bba328da148ddf6528d8241c13"}],"novaclient/exceptions.py":[{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"5a1ca12ec97f9f19333be7a794f24adbea7ab2fb","unresolved":false,"context_lines":[{"line_number":241,"context_line":"        self.retry_after \u003d 0"},{"line_number":242,"context_line":"        self._get_rate_limit(response)"},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"    def _get_rate_limit(self, resp):"},{"line_number":245,"context_line":"        if (resp is not None) and resp.headers:"},{"line_number":246,"context_line":"            utc_now \u003d timeutils.utcnow()"},{"line_number":247,"context_line":"            value \u003d resp.headers.get(\u0027Retry-After\u0027, \u00270\u0027)"}],"source_content_type":"text/x-python","patch_set":2,"id":"1a1ced50_bf5a5528","line":244,"updated":"2017-03-21 14:51:23.000000000","message":"Seems to me that this could be a function or static method that returns the retry_after value, rather than setting it this way.  Just a thought…","commit_id":"204f7243ca74bdbadc037ab7742b2eeed3811f7e"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"5a1ca12ec97f9f19333be7a794f24adbea7ab2fb","unresolved":false,"context_lines":[{"line_number":242,"context_line":"        self._get_rate_limit(response)"},{"line_number":243,"context_line":""},{"line_number":244,"context_line":"    def _get_rate_limit(self, resp):"},{"line_number":245,"context_line":"        if (resp is not None) and resp.headers:"},{"line_number":246,"context_line":"            utc_now \u003d timeutils.utcnow()"},{"line_number":247,"context_line":"            value \u003d resp.headers.get(\u0027Retry-After\u0027, \u00270\u0027)"},{"line_number":248,"context_line":"            try:"}],"source_content_type":"text/x-python","patch_set":2,"id":"1a1ced50_746ac4ef","line":245,"range":{"start_line":245,"start_character":11,"end_line":245,"end_character":29},"updated":"2017-03-21 14:51:23.000000000","message":"The parentheses are unnecessary here.","commit_id":"204f7243ca74bdbadc037ab7742b2eeed3811f7e"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"5a1ca12ec97f9f19333be7a794f24adbea7ab2fb","unresolved":false,"context_lines":[{"line_number":252,"context_line":"                else:"},{"line_number":253,"context_line":"                    self.retry_after \u003d 0"},{"line_number":254,"context_line":"            except ValueError:"},{"line_number":255,"context_line":"                self.retry_after \u003d int(value)"},{"line_number":256,"context_line":""},{"line_number":257,"context_line":""},{"line_number":258,"context_line":"# NotImplemented is a python keyword."}],"source_content_type":"text/x-python","patch_set":2,"id":"1a1ced50_ff676de6","line":255,"updated":"2017-03-21 14:51:23.000000000","message":"What if we get something that is neither an integer nor matches the strptime() format?  It shouldn\u0027t happen, but we have no control over the server.  I\u0027d suggest defaulting to 0 in that case.","commit_id":"204f7243ca74bdbadc037ab7742b2eeed3811f7e"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"e1ecb75945022ac382fe70320d1603fd19e2bc5b","unresolved":false,"context_lines":[{"line_number":236,"context_line":"            else:"},{"line_number":237,"context_line":"                retry_after \u003d 0"},{"line_number":238,"context_line":"        except ValueError:"},{"line_number":239,"context_line":"            retry_after \u003d 0"},{"line_number":240,"context_line":"    else:"},{"line_number":241,"context_line":"        retry_after \u003d 0"},{"line_number":242,"context_line":"    return retry_after"}],"source_content_type":"text/x-python","patch_set":22,"id":"df3967d1_a274eccf","line":239,"updated":"2017-08-04 13:57:06.000000000","message":"I thought this was supposed to also handle, e.g., \"Retry-After: 45\"?","commit_id":"c5376d7ad0bab2f6ebc4d90bb3563d5aa285b41b"},{"author":{"_account_id":22056,"name":"yushangbin","email":"shangbin.yu@easystack.cn","username":"yushangbin"},"change_message_id":"8854247fedc92e2bf362174631f942bf762cfe4a","unresolved":false,"context_lines":[{"line_number":236,"context_line":"            else:"},{"line_number":237,"context_line":"                retry_after \u003d 0"},{"line_number":238,"context_line":"        except ValueError:"},{"line_number":239,"context_line":"            retry_after \u003d 0"},{"line_number":240,"context_line":"    else:"},{"line_number":241,"context_line":"        retry_after \u003d 0"},{"line_number":242,"context_line":"    return retry_after"}],"source_content_type":"text/x-python","patch_set":22,"id":"bf3e73b7_e6c4ff42","line":239,"in_reply_to":"df3967d1_a274eccf","updated":"2017-08-06 05:28:40.000000000","message":"Done","commit_id":"c5376d7ad0bab2f6ebc4d90bb3563d5aa285b41b"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"d7330459d2221e07c127945f6c14469c4a182efd","unresolved":false,"context_lines":[{"line_number":236,"context_line":"            else:"},{"line_number":237,"context_line":"                retry_after \u003d 0"},{"line_number":238,"context_line":"        except ValueError:"},{"line_number":239,"context_line":"            retry_after \u003d int(value)"},{"line_number":240,"context_line":"    else:"},{"line_number":241,"context_line":"        retry_after \u003d 0"},{"line_number":242,"context_line":"    return retry_after"}],"source_content_type":"text/x-python","patch_set":23,"id":"bf3e73b7_602e9ea6","line":239,"updated":"2017-08-07 15:13:52.000000000","message":"That addresses my previous comment, but what happens if the header is corrupted?  Should we care about the ValueError that\u0027ll be raised in that instance?","commit_id":"1567ccccc2ad2e1d3d840b34dbaf6aaa2f4e0c6c"},{"author":{"_account_id":22056,"name":"yushangbin","email":"shangbin.yu@easystack.cn","username":"yushangbin"},"change_message_id":"5e047125844988a448efe5eb22ef7cf828d5076c","unresolved":false,"context_lines":[{"line_number":236,"context_line":"            else:"},{"line_number":237,"context_line":"                retry_after \u003d 0"},{"line_number":238,"context_line":"        except ValueError:"},{"line_number":239,"context_line":"            retry_after \u003d int(value)"},{"line_number":240,"context_line":"    else:"},{"line_number":241,"context_line":"        retry_after \u003d 0"},{"line_number":242,"context_line":"    return retry_after"}],"source_content_type":"text/x-python","patch_set":23,"id":"9f436f4f_56e130fe","line":239,"in_reply_to":"bf3e73b7_602e9ea6","updated":"2017-08-08 17:10:17.000000000","message":"OK, I think it should be done.","commit_id":"1567ccccc2ad2e1d3d840b34dbaf6aaa2f4e0c6c"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"ed4a3d004030dec383fd62c211ba9bfe2eaae5c8","unresolved":false,"context_lines":[{"line_number":240,"context_line":"            if value is None:"},{"line_number":241,"context_line":"                retry_after \u003d 0"},{"line_number":242,"context_line":"            else:"},{"line_number":243,"context_line":"                retry_after \u003d int(value)"},{"line_number":244,"context_line":"    else:"},{"line_number":245,"context_line":"        retry_after \u003d 0"},{"line_number":246,"context_line":"    return retry_after"}],"source_content_type":"text/x-python","patch_set":24,"id":"9f436f4f_f2d01053","line":243,"updated":"2017-08-09 15:30:29.000000000","message":"This logic doesn\u0027t address the header corruption I\u0027m talking about.  I\u0027m wondering what happens if the server sends, say, \"Retry-After: 45s\".  Obviously, no standards-compliant server should send such a value for that header, but servers are written by humans, and the client should try to handle the situation as gracefully as it can.  (For the record, I think, in addition to ignoring the malformed header value, it would be appropriate to issue a warning, as someone may be using novaclient to try to test their rate limiting proxy.)","commit_id":"0a93ee61099be5bba328da148ddf6528d8241c13"},{"author":{"_account_id":22056,"name":"yushangbin","email":"shangbin.yu@easystack.cn","username":"yushangbin"},"change_message_id":"2368f79484885af6d26d0bccbac73934317bf6a3","unresolved":false,"context_lines":[{"line_number":240,"context_line":"            if value is None:"},{"line_number":241,"context_line":"                retry_after \u003d 0"},{"line_number":242,"context_line":"            else:"},{"line_number":243,"context_line":"                retry_after \u003d int(value)"},{"line_number":244,"context_line":"    else:"},{"line_number":245,"context_line":"        retry_after \u003d 0"},{"line_number":246,"context_line":"    return retry_after"}],"source_content_type":"text/x-python","patch_set":24,"id":"9f436f4f_70e089fb","line":243,"in_reply_to":"9f436f4f_f2d01053","updated":"2017-08-10 04:54:43.000000000","message":"Kevin, thanks for your explaination, I\u0027ll try to do it, but may be need more of your review.","commit_id":"0a93ee61099be5bba328da148ddf6528d8241c13"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"ec4614503b7986205f208b8e53ea3f1d8ddbcf9b","unresolved":false,"context_lines":[{"line_number":245,"context_line":"            except ValueError:"},{"line_number":246,"context_line":"                msg \u003d (\"Retry-After in headers is malformed, \""},{"line_number":247,"context_line":"                       \"it should be something like \u00270\u0027, now the \""},{"line_number":248,"context_line":"                       \"value is set to 0.\")"},{"line_number":249,"context_line":"                LOG.warning(msg)"},{"line_number":250,"context_line":"                retry_after \u003d 0"},{"line_number":251,"context_line":"    else:"}],"source_content_type":"text/x-python","patch_set":25,"id":"9f436f4f_cef309e7","line":248,"updated":"2017-08-10 14:56:56.000000000","message":"This is what I was angling for.  Let\u0027s make the message read something like:\n\n    Retry-After header malformed; ignoring...","commit_id":"407c93af81fe7db6a7709e9f01232845bb7adae8"},{"author":{"_account_id":22056,"name":"yushangbin","email":"shangbin.yu@easystack.cn","username":"yushangbin"},"change_message_id":"d1ca03fd0627c7b4b86ead9785ec3328c38499a4","unresolved":false,"context_lines":[{"line_number":245,"context_line":"            except ValueError:"},{"line_number":246,"context_line":"                msg \u003d (\"Retry-After in headers is malformed, \""},{"line_number":247,"context_line":"                       \"it should be something like \u00270\u0027, now the \""},{"line_number":248,"context_line":"                       \"value is set to 0.\")"},{"line_number":249,"context_line":"                LOG.warning(msg)"},{"line_number":250,"context_line":"                retry_after \u003d 0"},{"line_number":251,"context_line":"    else:"}],"source_content_type":"text/x-python","patch_set":25,"id":"9f436f4f_c55e4711","line":248,"in_reply_to":"9f436f4f_cef309e7","updated":"2017-08-10 15:48:54.000000000","message":"Done. @Kevin","commit_id":"407c93af81fe7db6a7709e9f01232845bb7adae8"}],"novaclient/tests/unit/test_exceptions.py":[{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"5a1ca12ec97f9f19333be7a794f24adbea7ab2fb","unresolved":false,"context_lines":[{"line_number":64,"context_line":"    def test_from_response_ratelimit_gmt(self, mock_utcnow):"},{"line_number":65,"context_line":"        response \u003d requests.Response()"},{"line_number":66,"context_line":"        response.status_code \u003d 429"},{"line_number":67,"context_line":"        response.headers \u003d {\"Retry-After\": \"Wen, 20 Mar 2017 17:40:55 GMT\"}"},{"line_number":68,"context_line":"        body \u003d {\u0027keys\u0027: ({})}"},{"line_number":69,"context_line":"        ex \u003d exceptions.from_response(response, body)"},{"line_number":70,"context_line":"        self.assertEqual(85, ex.retry_after)"}],"source_content_type":"text/x-python","patch_set":2,"id":"1a1ced50_5f84015d","line":67,"range":{"start_line":67,"start_character":44,"end_line":67,"end_character":47},"updated":"2017-03-21 14:51:23.000000000","message":"\"Wen\"?  Shouldn\u0027t it be \"Wed\"?","commit_id":"204f7243ca74bdbadc037ab7742b2eeed3811f7e"},{"author":{"_account_id":23630,"name":"Tovin Seven","email":"tovin07@gmail.com","username":"tovin07"},"change_message_id":"027c5f4427c4581f0fe1f2480dfaf09e96a9152e","unresolved":false,"context_lines":[{"line_number":13,"context_line":"#    under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"import datetime"},{"line_number":16,"context_line":"import mock"},{"line_number":17,"context_line":"import requests"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"from novaclient import exceptions"}],"source_content_type":"text/x-python","patch_set":8,"id":"5f201791_fdf74d58","line":16,"range":{"start_line":16,"start_character":0,"end_line":16,"end_character":11},"updated":"2017-06-27 04:28:23.000000000","message":"you should add an empty line before this line to separate built-in libs vs third-party libs","commit_id":"5de6e5da2d909ab0b172ebc71e6a7faaf4548e30"},{"author":{"_account_id":22056,"name":"yushangbin","email":"shangbin.yu@easystack.cn","username":"yushangbin"},"change_message_id":"23df7e60b9f8928d2dba5eb053f7662500261fe6","unresolved":false,"context_lines":[{"line_number":13,"context_line":"#    under the License."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"import datetime"},{"line_number":16,"context_line":"import mock"},{"line_number":17,"context_line":"import requests"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"from novaclient import exceptions"}],"source_content_type":"text/x-python","patch_set":8,"id":"5f201791_a0f08afe","line":16,"range":{"start_line":16,"start_character":0,"end_line":16,"end_character":11},"in_reply_to":"5f201791_fdf74d58","updated":"2017-06-27 04:50:49.000000000","message":"Done. Hi Seven, thanks for your suggestion.","commit_id":"5de6e5da2d909ab0b172ebc71e6a7faaf4548e30"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"e1ecb75945022ac382fe70320d1603fd19e2bc5b","unresolved":false,"context_lines":[{"line_number":63,"context_line":"        self.assertIs(exceptions.RateLimit, type(ex))"},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"    @mock.patch(\u0027oslo_utils.timeutils.utcnow\u0027,"},{"line_number":66,"context_line":"                return_value\u003ddatetime.datetime(2017, 3, 20, 17, 40, 55))"},{"line_number":67,"context_line":"    def test_from_response_ratelimit_gmt(self, mock_utcnow):"},{"line_number":68,"context_line":"        response \u003d requests.Response()"},{"line_number":69,"context_line":"        response.status_code \u003d 429"}],"source_content_type":"text/x-python","patch_set":22,"id":"df3967d1_a20bcc27","line":66,"updated":"2017-08-04 13:57:06.000000000","message":"I think timeutils has a built-in means of overriding the time returned by such calls as utcnow.  You may want to investigate that…","commit_id":"c5376d7ad0bab2f6ebc4d90bb3563d5aa285b41b"},{"author":{"_account_id":22056,"name":"yushangbin","email":"shangbin.yu@easystack.cn","username":"yushangbin"},"change_message_id":"8854247fedc92e2bf362174631f942bf762cfe4a","unresolved":false,"context_lines":[{"line_number":63,"context_line":"        self.assertIs(exceptions.RateLimit, type(ex))"},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"    @mock.patch(\u0027oslo_utils.timeutils.utcnow\u0027,"},{"line_number":66,"context_line":"                return_value\u003ddatetime.datetime(2017, 3, 20, 17, 40, 55))"},{"line_number":67,"context_line":"    def test_from_response_ratelimit_gmt(self, mock_utcnow):"},{"line_number":68,"context_line":"        response \u003d requests.Response()"},{"line_number":69,"context_line":"        response.status_code \u003d 429"}],"source_content_type":"text/x-python","patch_set":22,"id":"bf3e73b7_86e1b3d3","line":66,"in_reply_to":"df3967d1_a20bcc27","updated":"2017-08-06 05:28:40.000000000","message":"Hi Kevin, you mean it\u0027s better to use set_time_override instead of utcnow?","commit_id":"c5376d7ad0bab2f6ebc4d90bb3563d5aa285b41b"}]}
