Skip to content

Set default --max-requests for API workers to prevent unbounded RSS growth#7529

Open
amasolov wants to merge 1 commit intopulp:mainfrom
amasolov:fix/default-max-requests
Open

Set default --max-requests for API workers to prevent unbounded RSS growth#7529
amasolov wants to merge 1 commit intopulp:mainfrom
amasolov:fix/default-max-requests

Conversation

@amasolov
Copy link
Copy Markdown

Summary

  • Set max_requests=10000 and max_requests_jitter=500 as defaults for API workers
  • Workers are gracefully recycled after ~10,000 requests, resetting accumulated glibc heap fragmentation
  • Defaults only apply when max_requests has not been explicitly configured (via CLI, config file, or GUNICORN_CMD_ARGS)

Context

Follow-up from the discussion in #7481 where @ggainey and @dralley agreed that setting sensible --max-requests defaults is the right approach. See #7482 for the full profiling data showing ~1 kB/request RSS growth from glibc heap fragmentation under normal Django ORM workload.

Implementation note

The defaults are set in PulpcoreApiApplication.load_app_specific_config() rather than as click option defaults to preserve the config precedence chain: if a user has already configured max_requests via a config file, GUNICORN_CMD_ARGS, or CLI flag, their value is respected and not overridden.

Test plan

  • Verify workers restart after ~10,000 requests (check gunicorn logs for worker boot messages)
  • Verify --max-requests 0 on CLI disables recycling
  • Verify GUNICORN_CMD_ARGS="--max-requests 5000" overrides the default
  • Verify existing test suite passes

📜 Checklist

  • Commits are cleanly separated with meaningful messages (simple features and bug fixes should be squashed to one commit)
  • A changelog entry or entries has been added for any significant changes
  • Follows the Pulp policy on AI Usage
  • (For new features) - User documentation and test coverage has been added

See: Pull Request Walkthrough

Made with Cursor

@amasolov amasolov force-pushed the fix/default-max-requests branch 3 times, most recently from b1b399a to b545426 Compare March 30, 2026 11:49
PulpApiWorker.__module__ + "." + PulpApiWorker.__qualname__,
enforced=True,
)
if self.cfg.max_requests == 0:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment describes disabling recycling by setting --max-requests 0, but it would seem like this would explicitly use the defaults in that scenario. Am I missing something?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

…rowth

API workers currently run with max_requests=0 (unlimited lifetime), which
means glibc heap fragmentation accumulates indefinitely and RSS grows
without bound (~1 kB/request from normal Django ORM alloc/dealloc churn).

Set max_requests=10000 and max_requests_jitter=500 as defaults for
PulpApiWorker when gunicorn's effective max_requests is still 0 and the
user did not pass --max-requests on the pulpcore-api CLI. An explicit
--max-requests 0 disables recycling (gunicorn semantics) and is not
overridden.

Workers are gracefully recycled after ~10000 requests, resetting
fragmented heap memory. Jitter prevents all workers from restarting
simultaneously.

Documented in docs/admin/learn/architecture.md.

closes pulp#7482

Assisted-by: Claude (Anthropic)
Made-with: Cursor
@amasolov
Copy link
Copy Markdown
Author

@dralley Good catch - I had that backwards in the first version.

Gunicorn already uses max_requests == 0 for "no recycling", and I was treating any 0 as "use our defaults", which would have stomped on someone who explicitly passes --max-requests 0 to turn recycling off.

I’ve changed it so we only apply the 10000/500 defaults when --max-requests wasn’t passed on the pulpcore-api CLI (None in the click options). If you pass --max-requests 0, we leave it alone. Updated the architecture note to say the same thing.

Latest push is one squashed commit with that fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants