Skip to content

fix(frontend): raise soft RLIMIT_NOFILE at startup to avoid accept() EMFILE spiral - #11802

Merged
dagil-nvidia merged 6 commits into
ai-dynamo:mainfrom
mikekg:fix/frontend-fd-limit
Jul 29, 2026
Merged

fix(frontend): raise soft RLIMIT_NOFILE at startup to avoid accept() EMFILE spiral#11802
dagil-nvidia merged 6 commits into
ai-dynamo:mainfrom
mikekg:fix/frontend-fd-limit

Conversation

@mikekg

@mikekg mikekg commented Jul 16, 2026

Copy link
Copy Markdown

Fixes the accept() failure spiral described in #11801.

The frontend's TCP accept loop (lib/runtime/src/pipeline/network/tcp/server.rs) retries accept() with no backoff on failure. Under high concurrency with a non-keep-alive HTTP client, established connections can reach roughly 2x the nominal benchmark concurrency, and the default soft RLIMIT_NOFILE (1024 on most distros) gets exhausted, causing accept() to fail with EMFILE in a tight zero-backoff loop that also floods stdout (observed 15.8GB/86.9GB logs within minutes).

This raises the process's soft RLIMIT_NOFILE at startup (components/src/dynamo/frontend/main.py), bounded by whatever hard limit the environment provides. No-op if the environment already has enough headroom. No changes to the accept-loop logic itself.

See #11801 for full repro details, environment, and logs.

Summary by CodeRabbit

  • Bug Fixes
    • Improved frontend startup reliability by automatically increasing the process file-descriptor limit when needed.
    • Respects the system’s maximum allowed limit and records the adjustment.

@mikekg
mikekg requested a review from a team as a code owner July 16, 2026 21:52
@mikekg
mikekg temporarily deployed to external_collaborator July 16, 2026 21:52 — with GitHub Actions Inactive
@mikekg
mikekg temporarily deployed to external_collaborator July 16, 2026 21:52 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown
Contributor

👋 Hi mikekg! Thank you for contributing to ai-dynamo/dynamo.

Just a reminder: The NVIDIA Test Github Validation CI runs an essential subset of the testing framework to quickly catch errors.Your PR reviewers may elect to test the changes comprehensively before approving your changes.

🚀

@github-actions github-actions Bot added external-contribution Pull request is from an external contributor frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` labels Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The frontend defines a target soft file-descriptor limit, raises the current limit within the hard-limit bound when needed, and performs this setup before launching the asynchronous runtime.

Changes

Frontend startup

Layer / File(s) Summary
File-descriptor limit configuration and startup wiring
components/src/dynamo/frontend/main.py
Adds FRONTEND_FD_LIMIT_TARGET and _raise_fd_limit(), which conditionally updates the soft RLIMIT_NOFILE limit and logs the change. main() invokes it before uvloop.run(async_main()).

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description does not follow the required template and is missing the Overview, Details, reviewer start, and Related Issues sections. Rewrite the PR description using the template, including Overview, Details, Where should reviewer start?, and Related Issues with either Closes #XXXX or a confirmed no-issue checkbox.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main change: raising the frontend soft RLIMIT_NOFILE at startup.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
components/src/dynamo/frontend/main.py (2)

64-64: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move resource to module scope.

This standard-library import is inside _raise_fd_limit(), hiding a module dependency. Add it with the existing standard-library imports and remove the function-local import.

As per coding guidelines, imports must remain at module top.

Proposed change
+# with the other standard-library imports
+import resource
+
 def _raise_fd_limit(target: int = FRONTEND_FD_LIMIT_TARGET) -> None:
-    import resource
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/src/dynamo/frontend/main.py` at line 64, Move the resource import
from inside _raise_fd_limit() to the module-level standard-library imports, and
remove the function-local import while leaving the function’s behavior
unchanged.

Sources: Coding guidelines, Path instructions


70-72: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use lazy logging formatting.

Pass values as logging arguments instead of constructing an f-string eagerly.

As per coding guidelines, logger calls must use lazy formatting.

Proposed change
         logger.info(
-            f"Raised RLIMIT_NOFILE soft limit {soft} -> {new_soft} (hard={hard})"
+            "Raised RLIMIT_NOFILE soft limit %s -> %s (hard=%s)",
+            soft,
+            new_soft,
+            hard,
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/src/dynamo/frontend/main.py` around lines 70 - 72, Update the
logger.info call reporting the RLIMIT_NOFILE change to use a format string with
soft, new_soft, and hard passed as logging arguments, eliminating the eagerly
constructed f-string while preserving the existing message.

Sources: Coding guidelines, Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/src/dynamo/frontend/main.py`:
- Around line 66-69: Update the RLIMIT_NOFILE handling around resource.getrlimit
so resource.RLIM_INFINITY, including negative sentinel representations, is
treated as an unlimited hard limit rather than passed to min. Preserve the
existing cap for finite hard limits, and add coverage for both finite and
unlimited cases.

---

Nitpick comments:
In `@components/src/dynamo/frontend/main.py`:
- Line 64: Move the resource import from inside _raise_fd_limit() to the
module-level standard-library imports, and remove the function-local import
while leaving the function’s behavior unchanged.
- Around line 70-72: Update the logger.info call reporting the RLIMIT_NOFILE
change to use a format string with soft, new_soft, and hard passed as logging
arguments, eliminating the eagerly constructed f-string while preserving the
existing message.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d2694af6-e839-4400-93f6-be2fcb3a3f5e

📥 Commits

Reviewing files that changed from the base of the PR and between 01d2cb2 and 4ff5352.

📒 Files selected for processing (1)
  • components/src/dynamo/frontend/main.py

Comment thread components/src/dynamo/frontend/main.py Outdated
@copy-pr-bot

copy-pr-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

…E spiral

The frontend's TCP accept loop (lib/runtime/src/pipeline/network/tcp/server.rs)
retries accept() with no backoff on failure. Under high concurrency with a
non-keep-alive HTTP client, established connections can reach roughly 2x the
nominal benchmark concurrency, and the default soft RLIMIT_NOFILE (1024 on
most distros) gets exhausted, causing accept() to fail with EMFILE in a tight
zero-backoff loop.

Raise the soft limit at process startup, bounded by the hard limit. No-op if
the environment already provides enough headroom.

See issue ai-dynamo#11801.

Signed-off-by: mikekg <mgschwind@nvidia.com>
@mikekg
mikekg force-pushed the fix/frontend-fd-limit branch from 4ff5352 to e724b1e Compare July 16, 2026 22:02
@mikekg
mikekg temporarily deployed to external_collaborator July 16, 2026 22:03 — with GitHub Actions Inactive
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Mike G <mgschwind+mikekg@nvidia.com>
@mikekg
mikekg temporarily deployed to external_collaborator July 16, 2026 22:46 — with GitHub Actions Inactive
@datadog-official

datadog-official Bot commented Jul 16, 2026

Copy link
Copy Markdown

🎯 Code Coverage (details)
Patch Coverage: 24.24%
Overall Coverage: 41.98% (-3.94%)

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 1626577 | Docs | Give us feedback!

@mikekg
mikekg temporarily deployed to external_collaborator July 16, 2026 22:55 — with GitHub Actions Inactive
Comment thread components/src/dynamo/frontend/main.py Outdated

@RitwijParmar RitwijParmar left a comment

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 EMFILE failure mode is real and the startup limit is a reasonable first layer. One portability issue needs attention before merge: resource is Unix-only, so importing it at module scope can make the frontend fail during import on Windows. I left an inline comment with the suggested lazy import and fallback. A small platform test would keep this safe across the supported runners.

mikekg added a commit to mikekg/dynamo that referenced this pull request Jul 20, 2026
`resource` is Unix-only, so a module-scope import broke main.py on Windows CI. Move the import into _raise_fd_limit and make the whole raise best-effort: no-op when resource is unavailable (Windows) or when setrlimit is denied (restricted env). Adds platform-safety unit tests.

Addresses review feedback on ai-dynamo#11802.

Signed-off-by: mikekg <mgschwind@nvidia.com>
@mikekg
mikekg temporarily deployed to external_collaborator July 20, 2026 21:27 — with GitHub Actions Inactive
@mikekg mikekg changed the title frontend: raise soft RLIMIT_NOFILE at startup to avoid accept() EMFILE spiral fix(frontend): raise soft RLIMIT_NOFILE at startup to avoid accept() EMFILE spiral Jul 20, 2026
Comment thread components/src/dynamo/frontend/main.py Outdated
Comment thread components/src/dynamo/frontend/main.py
mikekg added 2 commits July 20, 2026 14:35
Signed-off-by: Michael Gschwind <mgschwind@nvidia.com>
`resource` is Unix-only, so a module-scope import broke main.py on Windows CI. Move the import into _raise_fd_limit and make the whole raise best-effort: no-op when resource is unavailable (Windows) or when setrlimit is denied (restricted env). Adds platform-safety unit tests.

Addresses review feedback on ai-dynamo#11802.

Signed-off-by: mikekg <mgschwind@nvidia.com>
@github-actions github-actions Bot added the fix label Jul 20, 2026
Per review, allow operators to tune the RLIMIT_NOFILE target at deploy time via DYN_FRONTEND_FD_LIMIT_TARGET (default 8192). A non-positive or non-integer value disables the raise, so it can be turned off without a code change.

Signed-off-by: mikekg <mgschwind@nvidia.com>
@mikekg
mikekg force-pushed the fix/frontend-fd-limit branch from 58ea65e to f672fd8 Compare July 20, 2026 21:46
@pull-request-size pull-request-size Bot added size/L and removed size/M labels Jul 20, 2026
@mikekg
mikekg temporarily deployed to external_collaborator July 20, 2026 21:46 — with GitHub Actions Inactive
@rmccorm4

Copy link
Copy Markdown
Contributor

/ok to test f672fd8

Comment thread components/src/dynamo/frontend/main.py
RLIM_INFINITY is -1, so the old 'new_soft > soft' check saw an unlimited soft limit (-1) as smaller than the target and would setrlimit() it DOWN to 8192. Short-circuit when the soft limit is already RLIM_INFINITY.

Signed-off-by: mikekg <mgschwind@nvidia.com>
@mikekg
mikekg temporarily deployed to external_collaborator July 20, 2026 22:55 — with GitHub Actions Inactive
@biswapanda

Copy link
Copy Markdown
Contributor

/ok to test 1626577

@dagil-nvidia

Copy link
Copy Markdown
Collaborator

/ok to test 1626577

@dagil-nvidia
dagil-nvidia merged commit 99851d8 into ai-dynamo:main Jul 29, 2026
98 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external-contribution Pull request is from an external contributor fix frontend `python -m dynamo.frontend` and `dynamo-run in=http|text|grpc` size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants