Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES/7482.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Set default ``--max-requests 10000`` and ``--max-requests-jitter 500`` for API workers
to prevent unbounded RSS growth from glibc heap fragmentation over long-lived worker processes.
8 changes: 8 additions & 0 deletions docs/admin/learn/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ Pulp's REST API is a Django application that runs standalone using the `gunicorn
A simple way to run the REST API as a standalone service is using the provided `pulpcore-api`
entrypoint. It is `gunicorn` based and provides many of its options.

!!! note "API worker recycling"
By default, `pulpcore-api` enables gunicorn ``--max-requests`` and ``--max-requests-jitter`` so
worker processes are periodically replaced. That limits memory growth from allocator
fragmentation in long-lived workers. Override via gunicorn's usual mechanisms (CLI flags,
``GUNICORN_CMD_ARGS``, or a config file). To **disable** recycling and keep unlimited worker
lifetime, pass ``--max-requests 0`` on the ``pulpcore-api`` command line (gunicorn treats
``0`` as unlimited; Pulp only applies its own defaults when ``--max-requests`` was not passed
there). Disabling recycling is not recommended for production.

The REST API should only be deployed via the `pulpcore-api` entrypoint.

Expand Down
7 changes: 7 additions & 0 deletions pulpcore/app/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ def load_app_specific_config(self):
PulpApiWorker.__module__ + "." + PulpApiWorker.__qualname__,
enforced=True,
)
# Gunicorn's default for max_requests is 0 (unlimited worker lifetime). Apply Pulp defaults
# only when the user did not pass --max-requests on the pulpcore-api CLI. An explicit
# --max-requests 0 means "disable recycling" and must not be replaced.
if self.cfg.max_requests == 0 and self.options.get("max_requests") is None:
self.cfg.set("max_requests", 10000)
if self.options.get("max_requests_jitter") is None:
self.cfg.set("max_requests_jitter", 500)

def load(self):
using_pulp_api_worker.set(True)
Expand Down