prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  SystemExit: 1
  Sentry Issue: [SITE-1G](https://sentry.io/organizations/python-discord/issues/2623186847/?referrer=github_integration)
  
  ```
  SystemExit: 1
  (36 additional frame(s) were not displayed)
  ...
    File "urllib3/connectionpool.py", line 1010, in _validate_conn
      conn.connect()
    File "urllib3/connection.py", line 353, in connect
      conn = self._new_conn()
    File "urllib3/connection.py", line 169, in _new_conn
      conn = connection.create_connection(
    File "urllib3/util/connection.py", line 86, in create_connection
      sock.connect(sa)
    File "gunicorn/workers/base.py", line 201, in handle_abort
      sys.exit(1)
  ```
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `pydis_site/constants.py`
  Content:
  ```
  1 import os
  2 
  3 GIT_SHA = os.environ.get("GIT_SHA", "development")
  4 GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN")
  5
  ```
  
  Path: `pydis_site/apps/home/views/home.py`
  Content:
  ```
  1 import logging
  2 from typing import Dict, List
  3 
  4 import requests
  5 from django.core.handlers.wsgi import WSGIRequest
  6 from django.http import HttpResponse
  7 from django.shortcuts import render
  8 from django.utils import timezone
  9 from django.views import View
  10 
  11 from pydis_site.apps.home.models import RepositoryMetadata
  12 from pydis_site.constants import GITHUB_TOKEN
  13 
  14 log = logging.getLogger(__name__)
  15 
  16 
  17 class HomeView(View):
  18     """The main landing page for the website."""
  19 
  20     github_api = "https://api.github.com/users/python-discord/repos?per_page=100"
  21     repository_cache_ttl = 3600
  22 
  23     # Which of our GitHub repos should be displayed on the front page, and in which order?
  24     repos = [
  25         "python-discord/site",
  26         "python-discord/bot",
  27         "python-discord/snekbox",
  28         "python-discord/sir-lancebot",
  29         "python-discord/metricity",
  30         "python-discord/django-simple-bulma",
  31     ]
  32 
  33     def __init__(self):
  34         """Clean up stale RepositoryMetadata."""
  35         RepositoryMetadata.objects.exclude(repo_name__in=self.repos).delete()
  36 
  37         # If no token is defined (for example in local development), then
  38         # it does not make sense to pass the Authorization header. More
  39         # specifically, GitHub will reject any requests from us due to the
  40         # invalid header. We can make a limited number of anonymous requests
  41         # though, which is useful for testing.
  42         if GITHUB_TOKEN:
  43             self.headers = {"Authorization": f"token {GITHUB_TOKEN}"}
  44         else:
  45             self.headers = {}
  46 
  47     def _get_api_data(self) -> Dict[str, Dict[str, str]]:
  48         """
  49         Call the GitHub API and get information about our repos.
  50 
  51         If we're unable to get that info for any reason, return an empty dict.
  52         """
  53         repo_dict = {}
  54 
  55         # Fetch the data from the GitHub API
  56         api_data: List[dict] = requests.get(self.github_api, headers=self.headers).json()
  57 
  58         # Process the API data into our dict
  59         for repo in api_data:
  60             try:
  61                 full_name = repo["full_name"]
  62 
  63                 if full_name in self.repos:
  64                     repo_dict[full_name] = {
  65                         "full_name": repo["full_name"],
  66                         "description": repo["description"],
  67                         "language": repo["language"],
  68                         "forks_count": repo["forks_count"],
  69                         "stargazers_count": repo["stargazers_count"],
  70                     }
  71             # Something is not right about the API data we got back from GitHub.
  72             except (TypeError, ConnectionError, KeyError) as e:
  73                 log.error(
  74                     "Unable to parse the GitHub repository metadata from response!",
  75                     extra={
  76                         'api_data': api_data,
  77                         'error': e
  78                     }
  79                 )
  80                 continue
  81 
  82         return repo_dict
  83 
  84     def _get_repo_data(self) -> List[RepositoryMetadata]:
  85         """Build a list of RepositoryMetadata objects that we can use to populate the front page."""
  86         # First off, load the timestamp of the least recently updated entry.
  87         last_update = (
  88             RepositoryMetadata.objects.values_list("last_updated", flat=True)
  89             .order_by("last_updated").first()
  90         )
  91 
  92         # If we did not retrieve any results here, we should import them!
  93         if last_update is None:
  94 
  95             # Try to get new data from the API. If it fails, we'll return an empty list.
  96             # In this case, we simply don't display our projects on the site.
  97             api_repositories = self._get_api_data()
  98 
  99             # Create all the repodata records in the database.
  100             return RepositoryMetadata.objects.bulk_create(
  101                 RepositoryMetadata(
  102                     repo_name=api_data["full_name"],
  103                     description=api_data["description"],
  104                     forks=api_data["forks_count"],
  105                     stargazers=api_data["stargazers_count"],
  106                     language=api_data["language"],
  107                 )
  108                 for api_data in api_repositories.values()
  109             )
  110 
  111         # If the data is stale, we should refresh it.
  112         if (timezone.now() - last_update).seconds > self.repository_cache_ttl:
  113             # Try to get new data from the API. If it fails, return the cached data.
  114             api_repositories = self._get_api_data()
  115 
  116             if not api_repositories:
  117                 return RepositoryMetadata.objects.all()
  118 
  119             # Update or create all RepoData objects in self.repos
  120             database_repositories = []
  121             for api_data in api_repositories.values():
  122                 repo_data, _created = RepositoryMetadata.objects.update_or_create(
  123                     repo_name=api_data["full_name"],
  124                     defaults={
  125                         'repo_name': api_data["full_name"],
  126                         'description': api_data["description"],
  127                         'forks': api_data["forks_count"],
  128                         'stargazers': api_data["stargazers_count"],
  129                         'language': api_data["language"],
  130                     }
  131                 )
  132                 database_repositories.append(repo_data)
  133             return database_repositories
  134 
  135         # Otherwise, if the data is fresher than 2 minutes old, we should just return it.
  136         else:
  137             return RepositoryMetadata.objects.all()
  138 
  139     def get(self, request: WSGIRequest) -> HttpResponse:
  140         """Collect repo data and render the homepage view."""
  141         repo_data = self._get_repo_data()
  142         return render(request, "home/index.html", {"repo_data": repo_data})
  143 
  144 
  145 def timeline(request: WSGIRequest) -> HttpResponse:
  146     """Render timeline view."""
  147     return render(request, 'home/timeline.html')
  148
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/pydis_site/apps/home/views/home.py b/pydis_site/apps/home/views/home.py
  --- a/pydis_site/apps/home/views/home.py
  +++ b/pydis_site/apps/home/views/home.py
  @@ -9,7 +9,7 @@
   from django.views import View
   
   from pydis_site.apps.home.models import RepositoryMetadata
  -from pydis_site.constants import GITHUB_TOKEN
  +from pydis_site.constants import GITHUB_TOKEN, TIMEOUT_PERIOD
   
   log = logging.getLogger(__name__)
   
  @@ -51,9 +51,16 @@
           If we're unable to get that info for any reason, return an empty dict.
           """
           repo_dict = {}
  -
  -        # Fetch the data from the GitHub API
  -        api_data: List[dict] = requests.get(self.github_api, headers=self.headers).json()
  +        try:
  +            # Fetch the data from the GitHub API
  +            api_data: List[dict] = requests.get(
  +                self.github_api,
  +                headers=self.headers,
  +                timeout=TIMEOUT_PERIOD
  +            ).json()
  +        except requests.exceptions.Timeout:
  +            log.error("Request to fetch GitHub repository metadata for timed out!")
  +            return repo_dict
   
           # Process the API data into our dict
           for repo in api_data:
  diff --git a/pydis_site/constants.py b/pydis_site/constants.py
  --- a/pydis_site/constants.py
  +++ b/pydis_site/constants.py
  @@ -2,3 +2,5 @@
   
   GIT_SHA = os.environ.get("GIT_SHA", "development")
   GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN")
  +# How long to wait for synchronous requests before timing out
  +TIMEOUT_PERIOD = int(os.environ.get("TIMEOUT_PERIOD", 5))
  
verification_info: {"golden_diff": "diff --git a/pydis_site/apps/home/views/home.py b/pydis_site/apps/home/views/home.py\n--- a/pydis_site/apps/home/views/home.py\n+++ b/pydis_site/apps/home/views/home.py\n@@ -9,7 +9,7 @@\n from django.views import View\n \n from pydis_site.apps.home.models import RepositoryMetadata\n-from pydis_site.constants import GITHUB_TOKEN\n+from pydis_site.constants import GITHUB_TOKEN, TIMEOUT_PERIOD\n \n log = logging.getLogger(__name__)\n \n@@ -51,9 +51,16 @@\n         If we're unable to get that info for any reason, return an empty dict.\n         \"\"\"\n         repo_dict = {}\n-\n-        # Fetch the data from the GitHub API\n-        api_data: List[dict] = requests.get(self.github_api, headers=self.headers).json()\n+        try:\n+            # Fetch the data from the GitHub API\n+            api_data: List[dict] = requests.get(\n+                self.github_api,\n+                headers=self.headers,\n+                timeout=TIMEOUT_PERIOD\n+            ).json()\n+        except requests.exceptions.Timeout:\n+            log.error(\"Request to fetch GitHub repository metadata for timed out!\")\n+            return repo_dict\n \n         # Process the API data into our dict\n         for repo in api_data:\ndiff --git a/pydis_site/constants.py b/pydis_site/constants.py\n--- a/pydis_site/constants.py\n+++ b/pydis_site/constants.py\n@@ -2,3 +2,5 @@\n \n GIT_SHA = os.environ.get(\"GIT_SHA\", \"development\")\n GITHUB_TOKEN = os.environ.get(\"GITHUB_TOKEN\")\n+# How long to wait for synchronous requests before timing out\n+TIMEOUT_PERIOD = int(os.environ.get(\"TIMEOUT_PERIOD\", 5))\n", "issue": "SystemExit: 1\nSentry Issue: [SITE-1G](https://sentry.io/organizations/python-discord/issues/2623186847/?referrer=github_integration)\n\n```\nSystemExit: 1\n(36 additional frame(s) were not displayed)\n...\n  File \"urllib3/connectionpool.py\", line 1010, in _validate_conn\n    conn.connect()\n  File \"urllib3/connection.py\", line 353, in connect\n    conn = self._new_conn()\n  File \"urllib3/connection.py\", line 169, in _new_conn\n    conn = connection.create_connection(\n  File \"urllib3/util/connection.py\", line 86, in create_connection\n    sock.connect(sa)\n  File \"gunicorn/workers/base.py\", line 201, in handle_abort\n    sys.exit(1)\n```\n", "before_files": [{"content": "import os\n\nGIT_SHA = os.environ.get(\"GIT_SHA\", \"development\")\nGITHUB_TOKEN = os.environ.get(\"GITHUB_TOKEN\")\n", "path": "pydis_site/constants.py"}, {"content": "import logging\nfrom typing import Dict, List\n\nimport requests\nfrom django.core.handlers.wsgi import WSGIRequest\nfrom django.http import HttpResponse\nfrom django.shortcuts import render\nfrom django.utils import timezone\nfrom django.views import View\n\nfrom pydis_site.apps.home.models import RepositoryMetadata\nfrom pydis_site.constants import GITHUB_TOKEN\n\nlog = logging.getLogger(__name__)\n\n\nclass HomeView(View):\n    \"\"\"The main landing page for the website.\"\"\"\n\n    github_api = \"https://api.github.com/users/python-discord/repos?per_page=100\"\n    repository_cache_ttl = 3600\n\n    # Which of our GitHub repos should be displayed on the front page, and in which order?\n    repos = [\n        \"python-discord/site\",\n        \"python-discord/bot\",\n        \"python-discord/snekbox\",\n        \"python-discord/sir-lancebot\",\n        \"python-discord/metricity\",\n        \"python-discord/django-simple-bulma\",\n    ]\n\n    def __init__(self):\n        \"\"\"Clean up stale RepositoryMetadata.\"\"\"\n        RepositoryMetadata.objects.exclude(repo_name__in=self.repos).delete()\n\n        # If no token is defined (for example in local development), then\n        # it does not make sense to pass the Authorization header. More\n        # specifically, GitHub will reject any requests from us due to the\n        # invalid header. We can make a limited number of anonymous requests\n        # though, which is useful for testing.\n        if GITHUB_TOKEN:\n            self.headers = {\"Authorization\": f\"token {GITHUB_TOKEN}\"}\n        else:\n            self.headers = {}\n\n    def _get_api_data(self) -> Dict[str, Dict[str, str]]:\n        \"\"\"\n        Call the GitHub API and get information about our repos.\n\n        If we're unable to get that info for any reason, return an empty dict.\n        \"\"\"\n        repo_dict = {}\n\n        # Fetch the data from the GitHub API\n        api_data: List[dict] = requests.get(self.github_api, headers=self.headers).json()\n\n        # Process the API data into our dict\n        for repo in api_data:\n            try:\n                full_name = repo[\"full_name\"]\n\n                if full_name in self.repos:\n                    repo_dict[full_name] = {\n                        \"full_name\": repo[\"full_name\"],\n                        \"description\": repo[\"description\"],\n                        \"language\": repo[\"language\"],\n                        \"forks_count\": repo[\"forks_count\"],\n                        \"stargazers_count\": repo[\"stargazers_count\"],\n                    }\n            # Something is not right about the API data we got back from GitHub.\n            except (TypeError, ConnectionError, KeyError) as e:\n                log.error(\n                    \"Unable to parse the GitHub repository metadata from response!\",\n                    extra={\n                        'api_data': api_data,\n                        'error': e\n                    }\n                )\n                continue\n\n        return repo_dict\n\n    def _get_repo_data(self) -> List[RepositoryMetadata]:\n        \"\"\"Build a list of RepositoryMetadata objects that we can use to populate the front page.\"\"\"\n        # First off, load the timestamp of the least recently updated entry.\n        last_update = (\n            RepositoryMetadata.objects.values_list(\"last_updated\", flat=True)\n            .order_by(\"last_updated\").first()\n        )\n\n        # If we did not retrieve any results here, we should import them!\n        if last_update is None:\n\n            # Try to get new data from the API. If it fails, we'll return an empty list.\n            # In this case, we simply don't display our projects on the site.\n            api_repositories = self._get_api_data()\n\n            # Create all the repodata records in the database.\n            return RepositoryMetadata.objects.bulk_create(\n                RepositoryMetadata(\n                    repo_name=api_data[\"full_name\"],\n                    description=api_data[\"description\"],\n                    forks=api_data[\"forks_count\"],\n                    stargazers=api_data[\"stargazers_count\"],\n                    language=api_data[\"language\"],\n                )\n                for api_data in api_repositories.values()\n            )\n\n        # If the data is stale, we should refresh it.\n        if (timezone.now() - last_update).seconds > self.repository_cache_ttl:\n            # Try to get new data from the API. If it fails, return the cached data.\n            api_repositories = self._get_api_data()\n\n            if not api_repositories:\n                return RepositoryMetadata.objects.all()\n\n            # Update or create all RepoData objects in self.repos\n            database_repositories = []\n            for api_data in api_repositories.values():\n                repo_data, _created = RepositoryMetadata.objects.update_or_create(\n                    repo_name=api_data[\"full_name\"],\n                    defaults={\n                        'repo_name': api_data[\"full_name\"],\n                        'description': api_data[\"description\"],\n                        'forks': api_data[\"forks_count\"],\n                        'stargazers': api_data[\"stargazers_count\"],\n                        'language': api_data[\"language\"],\n                    }\n                )\n                database_repositories.append(repo_data)\n            return database_repositories\n\n        # Otherwise, if the data is fresher than 2 minutes old, we should just return it.\n        else:\n            return RepositoryMetadata.objects.all()\n\n    def get(self, request: WSGIRequest) -> HttpResponse:\n        \"\"\"Collect repo data and render the homepage view.\"\"\"\n        repo_data = self._get_repo_data()\n        return render(request, \"home/index.html\", {\"repo_data\": repo_data})\n\n\ndef timeline(request: WSGIRequest) -> HttpResponse:\n    \"\"\"Render timeline view.\"\"\"\n    return render(request, 'home/timeline.html')\n", "path": "pydis_site/apps/home/views/home.py"}], "after_files": [{"content": "import os\n\nGIT_SHA = os.environ.get(\"GIT_SHA\", \"development\")\nGITHUB_TOKEN = os.environ.get(\"GITHUB_TOKEN\")\n# How long to wait for synchronous requests before timing out\nTIMEOUT_PERIOD = int(os.environ.get(\"TIMEOUT_PERIOD\", 5))\n", "path": "pydis_site/constants.py"}, {"content": "import logging\nfrom typing import Dict, List\n\nimport requests\nfrom django.core.handlers.wsgi import WSGIRequest\nfrom django.http import HttpResponse\nfrom django.shortcuts import render\nfrom django.utils import timezone\nfrom django.views import View\n\nfrom pydis_site.apps.home.models import RepositoryMetadata\nfrom pydis_site.constants import GITHUB_TOKEN, TIMEOUT_PERIOD\n\nlog = logging.getLogger(__name__)\n\n\nclass HomeView(View):\n    \"\"\"The main landing page for the website.\"\"\"\n\n    github_api = \"https://api.github.com/users/python-discord/repos?per_page=100\"\n    repository_cache_ttl = 3600\n\n    # Which of our GitHub repos should be displayed on the front page, and in which order?\n    repos = [\n        \"python-discord/site\",\n        \"python-discord/bot\",\n        \"python-discord/snekbox\",\n        \"python-discord/sir-lancebot\",\n        \"python-discord/metricity\",\n        \"python-discord/django-simple-bulma\",\n    ]\n\n    def __init__(self):\n        \"\"\"Clean up stale RepositoryMetadata.\"\"\"\n        RepositoryMetadata.objects.exclude(repo_name__in=self.repos).delete()\n\n        # If no token is defined (for example in local development), then\n        # it does not make sense to pass the Authorization header. More\n        # specifically, GitHub will reject any requests from us due to the\n        # invalid header. We can make a limited number of anonymous requests\n        # though, which is useful for testing.\n        if GITHUB_TOKEN:\n            self.headers = {\"Authorization\": f\"token {GITHUB_TOKEN}\"}\n        else:\n            self.headers = {}\n\n    def _get_api_data(self) -> Dict[str, Dict[str, str]]:\n        \"\"\"\n        Call the GitHub API and get information about our repos.\n\n        If we're unable to get that info for any reason, return an empty dict.\n        \"\"\"\n        repo_dict = {}\n        try:\n            # Fetch the data from the GitHub API\n            api_data: List[dict] = requests.get(\n                self.github_api,\n                headers=self.headers,\n                timeout=TIMEOUT_PERIOD\n            ).json()\n        except requests.exceptions.Timeout:\n            log.error(\"Request to fetch GitHub repository metadata for timed out!\")\n            return repo_dict\n\n        # Process the API data into our dict\n        for repo in api_data:\n            try:\n                full_name = repo[\"full_name\"]\n\n                if full_name in self.repos:\n                    repo_dict[full_name] = {\n                        \"full_name\": repo[\"full_name\"],\n                        \"description\": repo[\"description\"],\n                        \"language\": repo[\"language\"],\n                        \"forks_count\": repo[\"forks_count\"],\n                        \"stargazers_count\": repo[\"stargazers_count\"],\n                    }\n            # Something is not right about the API data we got back from GitHub.\n            except (TypeError, ConnectionError, KeyError) as e:\n                log.error(\n                    \"Unable to parse the GitHub repository metadata from response!\",\n                    extra={\n                        'api_data': api_data,\n                        'error': e\n                    }\n                )\n                continue\n\n        return repo_dict\n\n    def _get_repo_data(self) -> List[RepositoryMetadata]:\n        \"\"\"Build a list of RepositoryMetadata objects that we can use to populate the front page.\"\"\"\n        # First off, load the timestamp of the least recently updated entry.\n        last_update = (\n            RepositoryMetadata.objects.values_list(\"last_updated\", flat=True)\n            .order_by(\"last_updated\").first()\n        )\n\n        # If we did not retrieve any results here, we should import them!\n        if last_update is None:\n\n            # Try to get new data from the API. If it fails, we'll return an empty list.\n            # In this case, we simply don't display our projects on the site.\n            api_repositories = self._get_api_data()\n\n            # Create all the repodata records in the database.\n            return RepositoryMetadata.objects.bulk_create(\n                RepositoryMetadata(\n                    repo_name=api_data[\"full_name\"],\n                    description=api_data[\"description\"],\n                    forks=api_data[\"forks_count\"],\n                    stargazers=api_data[\"stargazers_count\"],\n                    language=api_data[\"language\"],\n                )\n                for api_data in api_repositories.values()\n            )\n\n        # If the data is stale, we should refresh it.\n        if (timezone.now() - last_update).seconds > self.repository_cache_ttl:\n            # Try to get new data from the API. If it fails, return the cached data.\n            api_repositories = self._get_api_data()\n\n            if not api_repositories:\n                return RepositoryMetadata.objects.all()\n\n            # Update or create all RepoData objects in self.repos\n            database_repositories = []\n            for api_data in api_repositories.values():\n                repo_data, _created = RepositoryMetadata.objects.update_or_create(\n                    repo_name=api_data[\"full_name\"],\n                    defaults={\n                        'repo_name': api_data[\"full_name\"],\n                        'description': api_data[\"description\"],\n                        'forks': api_data[\"forks_count\"],\n                        'stargazers': api_data[\"stargazers_count\"],\n                        'language': api_data[\"language\"],\n                    }\n                )\n                database_repositories.append(repo_data)\n            return database_repositories\n\n        # Otherwise, if the data is fresher than 2 minutes old, we should just return it.\n        else:\n            return RepositoryMetadata.objects.all()\n\n    def get(self, request: WSGIRequest) -> HttpResponse:\n        \"\"\"Collect repo data and render the homepage view.\"\"\"\n        repo_data = self._get_repo_data()\n        return render(request, \"home/index.html\", {\"repo_data\": repo_data})\n\n\ndef timeline(request: WSGIRequest) -> HttpResponse:\n    \"\"\"Render timeline view.\"\"\"\n    return render(request, 'home/timeline.html')\n", "path": "pydis_site/apps/home/views/home.py"}]}