prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Protect against web/api 5xx responses
  When a build is attempted, but a web/api instance throws a 5xx response, a number of strange behaviors can result:
  - Builds will get stuck in triggered state
  - Builds will fail randomly when updating the api fails
  - 5xx responses will be returned from the web servers to users
  
  Part of the resolution to this may be defensive protection around intermittent 5xx responses. This may take some operation changes as well though, as our load balancer should really assume a 5xx response is enough to dislodge the server from the lb group.
  
  Raised from #2255 
  
  
  </issue>
  <code>
  [start of readthedocs/restapi/client.py]
  1 # -*- coding: utf-8 -*-
  2 
  3 """Simple client to access our API with Slumber credentials."""
  4 
  5 from __future__ import (
  6     absolute_import,
  7     division,
  8     print_function,
  9     unicode_literals,
  10 )
  11 
  12 import logging
  13 
  14 import requests
  15 from django.conf import settings
  16 from requests_toolbelt.adapters import host_header_ssl
  17 from rest_framework.renderers import JSONRenderer
  18 from slumber import API, serialize
  19 
  20 log = logging.getLogger(__name__)
  21 
  22 PRODUCTION_DOMAIN = getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org')
  23 API_HOST = getattr(settings, 'SLUMBER_API_HOST', 'https://readthedocs.org')
  24 USER = getattr(settings, 'SLUMBER_USERNAME', None)
  25 PASS = getattr(settings, 'SLUMBER_PASSWORD', None)
  26 
  27 
  28 class DrfJsonSerializer(serialize.JsonSerializer):
  29 
  30     """Additional serialization help from the DRF renderer"""
  31 
  32     key = 'json-drf'
  33 
  34     def dumps(self, data):
  35         """Used to be able to render datetime objects."""
  36         return JSONRenderer().render(data)
  37 
  38 
  39 def setup_api():
  40     session = requests.Session()
  41     if API_HOST.startswith('https'):
  42         # Only use the HostHeaderSSLAdapter for HTTPS connections
  43         adapter_class = host_header_ssl.HostHeaderSSLAdapter
  44     else:
  45         adapter_class = requests.adapters.HTTPAdapter
  46 
  47     session.mount(
  48         API_HOST,
  49         adapter_class(max_retries=3),
  50     )
  51     session.headers.update({'Host': PRODUCTION_DOMAIN})
  52     api_config = {
  53         'base_url': '%s/api/v2/' % API_HOST,
  54         'serializer': serialize.Serializer(
  55             default='json-drf',
  56             serializers=[
  57                 serialize.JsonSerializer(),
  58                 DrfJsonSerializer(),
  59             ],
  60         ),
  61         'session': session,
  62     }
  63     if USER and PASS:
  64         log.debug(
  65             'Using slumber v2 with user %s, pointed at %s',
  66             USER,
  67             API_HOST,
  68         )
  69         session.auth = (USER, PASS)
  70     else:
  71         log.warning('SLUMBER_USERNAME/PASSWORD settings are not set')
  72     return API(**api_config)
  73 
  74 
  75 api = setup_api()
  76
  [end of readthedocs/restapi/client.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/readthedocs/restapi/client.py b/readthedocs/restapi/client.py
  --- a/readthedocs/restapi/client.py
  +++ b/readthedocs/restapi/client.py
  @@ -13,6 +13,7 @@
   
   import requests
   from django.conf import settings
  +from requests.packages.urllib3.util.retry import Retry  # noqa
   from requests_toolbelt.adapters import host_header_ssl
   from rest_framework.renderers import JSONRenderer
   from slumber import API, serialize
  @@ -44,9 +45,21 @@
       else:
           adapter_class = requests.adapters.HTTPAdapter
   
  +    # Define a retry mechanism trying to attempt to not fail in the first
  +    # error. Builders hit this issue frequently because the webs are high loaded
  +    retry = Retry(
  +        total=3,
  +        read=3,
  +        connect=3,
  +        status=3,
  +        backoff_factor=0.5,  # 0.5, 1, 2 seconds
  +        method_whitelist=('GET', 'PUT', 'PATCH', 'POST'),
  +        status_forcelist=(408, 413, 429, 500, 502, 503, 504),
  +    )
  +
       session.mount(
           API_HOST,
  -        adapter_class(max_retries=3),
  +        adapter_class(max_retries=retry),
       )
       session.headers.update({'Host': PRODUCTION_DOMAIN})
       api_config = {
  
verification_info: {"golden_diff": "diff --git a/readthedocs/restapi/client.py b/readthedocs/restapi/client.py\n--- a/readthedocs/restapi/client.py\n+++ b/readthedocs/restapi/client.py\n@@ -13,6 +13,7 @@\n \n import requests\n from django.conf import settings\n+from requests.packages.urllib3.util.retry import Retry  # noqa\n from requests_toolbelt.adapters import host_header_ssl\n from rest_framework.renderers import JSONRenderer\n from slumber import API, serialize\n@@ -44,9 +45,21 @@\n     else:\n         adapter_class = requests.adapters.HTTPAdapter\n \n+    # Define a retry mechanism trying to attempt to not fail in the first\n+    # error. Builders hit this issue frequently because the webs are high loaded\n+    retry = Retry(\n+        total=3,\n+        read=3,\n+        connect=3,\n+        status=3,\n+        backoff_factor=0.5,  # 0.5, 1, 2 seconds\n+        method_whitelist=('GET', 'PUT', 'PATCH', 'POST'),\n+        status_forcelist=(408, 413, 429, 500, 502, 503, 504),\n+    )\n+\n     session.mount(\n         API_HOST,\n-        adapter_class(max_retries=3),\n+        adapter_class(max_retries=retry),\n     )\n     session.headers.update({'Host': PRODUCTION_DOMAIN})\n     api_config = {\n", "issue": "Protect against web/api 5xx responses\nWhen a build is attempted, but a web/api instance throws a 5xx response, a number of strange behaviors can result:\n- Builds will get stuck in triggered state\n- Builds will fail randomly when updating the api fails\n- 5xx responses will be returned from the web servers to users\n\nPart of the resolution to this may be defensive protection around intermittent 5xx responses. This may take some operation changes as well though, as our load balancer should really assume a 5xx response is enough to dislodge the server from the lb group.\n\nRaised from #2255 \n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n\"\"\"Simple client to access our API with Slumber credentials.\"\"\"\n\nfrom __future__ import (\n    absolute_import,\n    division,\n    print_function,\n    unicode_literals,\n)\n\nimport logging\n\nimport requests\nfrom django.conf import settings\nfrom requests_toolbelt.adapters import host_header_ssl\nfrom rest_framework.renderers import JSONRenderer\nfrom slumber import API, serialize\n\nlog = logging.getLogger(__name__)\n\nPRODUCTION_DOMAIN = getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org')\nAPI_HOST = getattr(settings, 'SLUMBER_API_HOST', 'https://readthedocs.org')\nUSER = getattr(settings, 'SLUMBER_USERNAME', None)\nPASS = getattr(settings, 'SLUMBER_PASSWORD', None)\n\n\nclass DrfJsonSerializer(serialize.JsonSerializer):\n\n    \"\"\"Additional serialization help from the DRF renderer\"\"\"\n\n    key = 'json-drf'\n\n    def dumps(self, data):\n        \"\"\"Used to be able to render datetime objects.\"\"\"\n        return JSONRenderer().render(data)\n\n\ndef setup_api():\n    session = requests.Session()\n    if API_HOST.startswith('https'):\n        # Only use the HostHeaderSSLAdapter for HTTPS connections\n        adapter_class = host_header_ssl.HostHeaderSSLAdapter\n    else:\n        adapter_class = requests.adapters.HTTPAdapter\n\n    session.mount(\n        API_HOST,\n        adapter_class(max_retries=3),\n    )\n    session.headers.update({'Host': PRODUCTION_DOMAIN})\n    api_config = {\n        'base_url': '%s/api/v2/' % API_HOST,\n        'serializer': serialize.Serializer(\n            default='json-drf',\n            serializers=[\n                serialize.JsonSerializer(),\n                DrfJsonSerializer(),\n            ],\n        ),\n        'session': session,\n    }\n    if USER and PASS:\n        log.debug(\n            'Using slumber v2 with user %s, pointed at %s',\n            USER,\n            API_HOST,\n        )\n        session.auth = (USER, PASS)\n    else:\n        log.warning('SLUMBER_USERNAME/PASSWORD settings are not set')\n    return API(**api_config)\n\n\napi = setup_api()\n", "path": "readthedocs/restapi/client.py"}]}