We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `readthedocs/restapi/client.py`
Content:
```
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 FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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 = {

{"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"}], "after_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.packages.urllib3.util.retry import Retry  # noqa\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    # 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=retry),\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"}]}