summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGauvain Pocentek <gauvain@pocentek.net>2018-04-24 11:25:08 +0200
committerGitHub <noreply@github.com>2018-04-24 11:25:08 +0200
commit86a825143fdae82d231c2c3589d81b26c8c3ab81 (patch)
treed22fba22c60acb27edb158df0b808f8748f1534e
parent25ed8e73f352b7f542a418c4ca2c802e3d90d06f (diff)
parente216f06d4d25d37a67239e93a8e2e400552be396 (diff)
downloadgitlab-86a825143fdae82d231c2c3589d81b26c8c3ab81.tar.gz
Merge pull request #488 from siemens/feat/rate-limit
feat: obey the rate limit
-rw-r--r--docs/api-usage.rst23
-rw-r--r--gitlab/__init__.py44
-rw-r--r--tools/python_test_v4.py25
3 files changed, 76 insertions, 16 deletions
diff --git a/docs/api-usage.rst b/docs/api-usage.rst
index 925f8bb..6513c9d 100644
--- a/docs/api-usage.rst
+++ b/docs/api-usage.rst
@@ -326,3 +326,26 @@ The following sample illustrates how to use a client-side certificate:
Reference:
http://docs.python-requests.org/en/master/user/advanced/#client-side-certificates
+
+Rate limits
+-----------
+
+python-gitlab will obey the rate limit of the GitLab server by default.
+On receiving a 429 response (Too Many Requests), python-gitlab will sleep for the amount of time
+in the Retry-After header, that GitLab sends back.
+
+If you don't want to wait, you can disable the rate-limiting feature, by supplying the
+``obey_rate_limit`` argument.
+
+.. code-block:: python
+
+ import gitlab
+ import requests
+
+ gl = gitlab.gitlab(url, token, api_version=4)
+ gl.projects.list(all=True, obey_rate_limit=False)
+
+
+.. warning::
+
+ You will get an Exception, if you then go over the rate limit of your GitLab instance.
diff --git a/gitlab/__init__.py b/gitlab/__init__.py
index 1658c39..b8a6e30 100644
--- a/gitlab/__init__.py
+++ b/gitlab/__init__.py
@@ -23,6 +23,7 @@ import inspect
import itertools
import json
import re
+import time
import warnings
import requests
@@ -698,24 +699,35 @@ class Gitlab(object):
prepped.url = sanitized_url(prepped.url)
settings = self.session.merge_environment_settings(
prepped.url, {}, streamed, verify, None)
- result = self.session.send(prepped, timeout=timeout, **settings)
- if 200 <= result.status_code < 300:
- return result
+ # obey the rate limit by default
+ obey_rate_limit = kwargs.get("obey_rate_limit", True)
- try:
- error_message = result.json()['message']
- except (KeyError, ValueError, TypeError):
- error_message = result.content
-
- if result.status_code == 401:
- raise GitlabAuthenticationError(response_code=result.status_code,
- error_message=error_message,
- response_body=result.content)
-
- raise GitlabHttpError(response_code=result.status_code,
- error_message=error_message,
- response_body=result.content)
+ while True:
+ result = self.session.send(prepped, timeout=timeout, **settings)
+
+ if 200 <= result.status_code < 300:
+ return result
+
+ if 429 == result.status_code and obey_rate_limit:
+ wait_time = int(result.headers["Retry-After"])
+ time.sleep(wait_time)
+ continue
+
+ try:
+ error_message = result.json()['message']
+ except (KeyError, ValueError, TypeError):
+ error_message = result.content
+
+ if result.status_code == 401:
+ raise GitlabAuthenticationError(
+ response_code=result.status_code,
+ error_message=error_message,
+ response_body=result.content)
+
+ raise GitlabHttpError(response_code=result.status_code,
+ error_message=error_message,
+ response_body=result.content)
def http_get(self, path, query_data={}, streamed=False, **kwargs):
"""Make a GET request to the Gitlab server.
diff --git a/tools/python_test_v4.py b/tools/python_test_v4.py
index 695722f..83dd967 100644
--- a/tools/python_test_v4.py
+++ b/tools/python_test_v4.py
@@ -646,3 +646,28 @@ gl.user_activities.list()
# events
gl.events.list()
+
+# rate limit
+settings = gl.settings.get()
+settings.throttle_authenticated_api_enabled = True
+settings.throttle_authenticated_api_requests_per_period = 1
+settings.throttle_authenticated_api_period_in_seconds = 3
+settings.save()
+projects = list()
+for i in range(0, 20):
+ projects.append(gl.projects.create(
+ {'name': str(i) + "ok"}))
+
+error_message = None
+for i in range(20, 40):
+ try:
+ projects.append(
+ gl.projects.create(
+ {'name': str(i) + 'shouldfail'}, obey_rate_limit=False))
+ except gitlab.GitlabCreateError as e:
+ error_message = e.error_message
+ break
+assert 'Retry later' in error_message
+[current_project.delete() for current_project in projects]
+settings.throttle_authenticated_api_enabled = False
+settings.save()