Frequent Service Restarts and High Memory Usage on Free Hosting (Render/Railway)

Frequent Service Restarts and High Memory Usage on Free Hosting (Render/Railway)

Context:

I am running a Python web application hosted on either Render using their free-tier plans. The app fetches data from a Supabase database via multiple API calls and processes podcast RSS feed information.

Issue:

The application frequently restarts, and I see logs indicating worker processes are being killed, likely due to exceeding memory limits. Additionally, the app makes a high volume of HTTP requests to Supabase in quick succession. While these requests succeed (HTTP 200 OK), the hosting platform may not have sufficient resources to handle this load effectively.

Logs:

Some of the logs I encounter:

yaml

Copy code

[2024-11-28 07:59:12 +0000] [1] [ERROR] Worker (pid:5) was sent SIGKILL! Perhaps out of memory?
[2024-11-28 07:59:14,277 - httpx - INFO - HTTP Request: GET https://xhiqvdyqaaowxptzupdf.supabase.co/rest/v1/podcasts?select=...
[2024-11-28 11:30:59,033 - app - INFO - Response status: 302 FOUND
2024-11-28 12:35:03,860 - httpx - INFO - HTTP Request: POST https://xhiqvdyqaaowxptzupdf.supabase.co/rest/v1/episodes "HTTP/2 201 Created"
2024-11-28 12:35:04,383 - httpx - INFO - HTTP Request: POST https://xhiqvdyqaaowxptzupdf.supabase.co/rest/v1/episodes "HTTP/2 201 Created"
2024-11-28 12:35:04,384 - main - INFO - Processed podcast: The Propcast
2024-11-28 12:35:04,633 - httpx - INFO - HTTP Request: GET https://xhiqvdyqaaowxptzupdf.supabase.co/rest/v1/podcasts?select=%2A&rss_feed=eq.https%3A%2F%2Ffeeds.buzzsprout.com%2F1608046.rss&client_id=eq.6 "HTTP/2 200 OK"
2024-11-28 12:35:05,096 - httpx - INFO - HTTP Request: GET https://xhiqvdyqaaowxptzupdf.supabase.co/rest/v1/podcasts?select=%2A&rss_feed=eq.https%3A%2F%2Ffeeds.buzzsprout.com%2F1608046.rss&client_id=neq.6 "HTTP/2 200 OK"
2024-11-28 12:35:05,378 - httpx - INFO - HTTP Request: POST https://xhiqvdyqaaowxptzupdf.supabase.co/rest/v1/podcasts "HTTP/2 201 Created"
2024-11-28 12:35:06,402 - httpx - INFO - HTTP Request: PATCH https://xhiqvdyqaaowxptzupdf.supabase.co/rest/v1/podcasts?id=eq.369 "HTTP/2 200 OK"
[2024-11-28 12:35:08 +0000] [95] [CRITICAL] WORKER TIMEOUT (pid:110)
127.0.0.1 - - [28/Nov/2024:12:35:08 +0000] "POST /upload_podcast HTTP/1.1" 500 0 "-" "-"
[2024-11-28 12:35:08 +0000] [110] [ERROR] Error handling request /upload_podcast
Traceback (most recent call last):
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/gunicorn/workers/sync.py", line 134, in handle
    self.handle_request(listener, req, client, addr)
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/gunicorn/workers/sync.py", line 177, in handle_request
    respiter = self.wsgi(environ, resp.start_response)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/flask/app.py", line 1478, in __call__
    return self.wsgi_app(environ, start_response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/flask/app.py", line 1455, in wsgi_app
    response = self.full_dispatch_request()
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/flask/app.py", line 867, in full_dispatch_request
    rv = self.dispatch_request()
         ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/flask/app.py", line 852, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/routes.py", line 210, in upload_podcast
    process_podcast(new_podcast_data, supabase)
  File "/opt/render/project/src/main.py", line 109, in process_podcast
    episode_embedding = create_embedding(episode_data['Description'])
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/utils.py", line 29, in create_embedding
    response = openai.Embedding.create(
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/openai/api_resources/embedding.py", line 33, in create
    response = super().create(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/openai/api_resources/abstract/engine_api_resource.py", line 153, in create
    response, _, api_key = requestor.request(
                           ^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/openai/api_requestor.py", line 288, in request
    result = self.request_raw(
             ^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/openai/api_requestor.py", line 596, in request_raw
    result = _thread_context.session.request(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/requests/sessions.py", line 589, in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/requests/sessions.py", line 703, in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/requests/adapters.py", line 486, in send
    resp = conn.urlopen(
           ^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/urllib3/connectionpool.py", line 789, in urlopen
    response = self._make_request(
               ^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/urllib3/connectionpool.py", line 536, in _make_request
    response = conn.getresponse()
               ^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/urllib3/connection.py", line 507, in getresponse
    httplib_response = super().getresponse()
                       ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/http/client.py", line 1395, in getresponse
    response.begin()
  File "/usr/local/lib/python3.11/http/client.py", line 325, in begin
    version, status, reason = self._read_status()
                              ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/http/client.py", line 286, in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/socket.py", line 718, in readinto
    return self._sock.recv_into(b)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/ssl.py", line 1314, in recv_into
    return self.read(nbytes, buffer)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.11/ssl.py", line 1166, in read
    return self._sslobj.read(len, buffer)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/render/project/src/.venv/lib/python3.11/site-packages/gunicorn/workers/base.py", line 204, in handle_abort
    sys.exit(1)
SystemExit: 1
[2024-11-28 12:35:08 +0000] [110] [INFO] Worker exiting (pid: 110)
[2024-11-28 12:35:09 +0000] [95] [ERROR] Worker (pid:110) was sent SIGKILL! Perhaps out of memory?
[2024-11-28 12:35:09 +0000] [114] [INFO] Booting worker with pid: 114

Key Details:

  • Hosting Platform: Render/Railway (free tier)
  • Database: Supabase
  • Logs suggest successful API responses (HTTP 200 OK), but the app restarts frequently.

What I’ve Tried:

  • Verified API responses are correct.
  • Confirmed that free-tier hosting resources might not limiting me
  • Reviewed logs to identify potential memory leaks or inefficient processing.

Questions:

  1. How can I optimize my application to work within the constraints of free-tier hosting?
  2. Should I consider batching API calls or implementing a caching mechanism to reduce the load on both the database and hosting server?
  3. Are there alternative ways to debug or profile the memory usage of my application in this environment?
  4. Is upgrading to a paid plan the best solution, or are there coding optimizations I can try first?

What about Unicorn config perhaps?
https://docs.gunicorn.org/en/stable/settings.html#timeout