Skip to content

Size FastAGI listen backlog via kernel cap instead of sysctl#65

Merged
itg-karthicr merged 3 commits into
masterfrom
fix/somaxconn-listen-backlog
Jun 25, 2026
Merged

Size FastAGI listen backlog via kernel cap instead of sysctl#65
itg-karthicr merged 3 commits into
masterfrom
fix/somaxconn-listen-backlog

Conversation

@itg-karthicr

Copy link
Copy Markdown
Contributor

Closes #32.

Background

_ThreadedTCPServer.get_somaxconn() shelled out to sysctl to read the system somaxconn, parsed OS-specific output (= on Linux, : on macOS), branched on platform.system(), and raised NotImplementedError on any host that was neither Linux nor macOS. So FastAGIServer could not start on Windows, BSD, or anything else — the "Linux and macOS only" caveat in the docs was a real functional restriction, not just documentation.

The issue thread debated socket.SOMAXCONN (a small compile-time constant, 128 historically, 4096 since Linux 5.4) versus reading the live runtime value. The maintainer's requirement was legitimate: the server must pick up an administrator's tuned-up net.core.somaxconn, which the constant does not reflect.

Approach

Reading the value is unnecessary. listen() already caps the backlog to the live system maximum (net.core.somaxconn on Linux, kern.ipc.somaxconn on macOS/BSD), so passing a value at or above that maximum yields exactly the maximum. Pass the largest value the call accepts and let the kernel clamp:

_LISTEN_BACKLOG = 2**31 - 1  # INT_MAX; the kernel caps this to the live somaxconn
...
self.request_queue_size = _LISTEN_BACKLOG

This is functionally identical to the old sysctl read on every configuration (both end up at min(what_we_pass, live_somaxconn)), but:

  • It tracks a tuned-up somaxconn automatically, with no per-start lookup.
  • It runs on every platform (removes the NotImplementedError crash and the docs caveat).
  • It drops the sysctl subprocess and the platform/socket/subprocess imports.

Why INT_MAX and not 65535: on modern kernels somaxconn is a 32-bit value (max 2147483647) that an administrator can tune above 65535, so any fixed ceiling could undershoot a tuned host. INT_MAX cannot — the kernel's own limit is then the only cap. The full rationale lives in the _LISTEN_BACKLOG comment.

Verified: listen() clamps (does not reject) a large backlog on Linux (net.core.somaxconn) and on macOS/BSD (kern.ipc.somaxconn, per the FreeBSD listen(2) semantics and regression test). The new binding test exercises this on the CI platform.

Tests

New tests/test_fastagi_server.py:

  • The server sets request_queue_size to INT_MAX; binding on an ephemeral port also proves listen() accepts the value rather than rejecting it.
  • The sysctl-spawning helper is gone (regression guard).

Full suite: 55 passing, ruff clean.

Docs

README, AGENTS.md, and CHANGELOG updated to describe the kernel-cap approach and remove the Linux/macOS-only restriction.

itg-karthicr and others added 2 commits June 24, 2026 22:49
get_somaxconn() shelled out to `sysctl` and parsed OS-specific output to read
the system somaxconn, branched on Linux vs Darwin, and raised
NotImplementedError on every other platform -- so FastAGIServer could not even
start on, e.g., Windows or BSD.

Reading the value is unnecessary. listen() already caps the backlog to the
live system maximum, so passing the largest value the call accepts yields
exactly that maximum and still tracks an administrator's tuned-up somaxconn
automatically. Set request_queue_size to INT_MAX (2**31 - 1) and let the
kernel clamp it.

INT_MAX rather than a fixed ceiling like 65535: on modern kernels somaxconn is
a 32-bit value that can be tuned above 65535, so any fixed ceiling could
undershoot; the kernel's own limit is the only safe cap. Verified that
listen() clamps (not rejects) a large backlog on Linux and on macOS/BSD.

Removes the platform/socket/subprocess imports (only get_somaxconn used them)
and the Linux/macOS-only restriction from the README and AGENTS docs. The
_LISTEN_BACKLOG constant carries the full rationale inline.

Add tests: the server sets request_queue_size to INT_MAX (binding on an
ephemeral port also proves listen() accepts it), and the sysctl helper is gone.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…review)

Review panel convergence (all comment/test polish, no behavior change):
- Extend the _LISTEN_BACKLOG comment with two facts the edge-case lane
  verified: the value must be exactly INT_MAX because CPython raises
  OverflowError for a listen() backlog above a signed 32-bit int (so a future
  "round up" would crash startup), and Windows accepts INT_MAX not via a
  somaxconn clamp but because Winsock's SOMAXCONN constant is itself 0x7fffffff,
  a sentinel meaning "use a maximum reasonable backlog".
- Test: import and assert against _LISTEN_BACKLOG instead of re-hardcoding the
  literal, and assert it exceeds 65535 so the "no fixed ceiling" rationale is
  executable.
- Test: also assert the module no longer imports subprocess/platform, a
  behavioral guard against reintroducing the shell-out that survives a rename
  of the old helper.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@itg-karthicr itg-karthicr left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review panel for PR #65.

critical
None.

warning

  • tests/test_fastagi_server.py:17: The regression test only checks _LISTEN_BACKLOG > 65535. A future fixed ceiling such as 1000000 passes this test and still breaks the documented INT_MAX contract from pystrix/agi/fastagi.py:65. Suggested fix: assert _LISTEN_BACKLOG == 2**31 - 1.

info

  • pystrix/agi/fastagi.py:74, README.md:83, CHANGELOG.md:13, AGENTS.md:70: The wording says the kernel caps to live somaxconn in every case, but pystrix/agi/fastagi.py:69 says Windows uses the Winsock INT_MAX sentinel instead. Suggested fix: say Unix-like platforms clamp to live somaxconn, and Windows uses the Winsock sentinel.

verification

  • pytest -q: 55 passed, outside sandbox.
  • pytest -q tests/test_fastagi_server.py: 2 passed, outside sandbox.
  • ruff check .: passed.
  • ruff format --check .: passed.
  • Local socket probe on Darwin 25.5.0: listen(2**31 - 1) accepted, and listen(2**31) raised OverflowError.

Comment thread tests/test_fastagi_server.py Outdated
assert server.request_queue_size == _LISTEN_BACKLOG
# A fixed ceiling like 65535 could undershoot a tuned-up somaxconn; the
# backlog must exceed it so the kernel's own limit is the only cap.
assert _LISTEN_BACKLOG > 65535

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The regression needs to lock the exact contract here. _LISTEN_BACKLOG > 65535 still passes for a fixed ceiling like 1000000, but the production comment says the value must be exactly INT_MAX. Suggested fix: assert _LISTEN_BACKLOG == 2**31 - 1.

Comment thread pystrix/agi/fastagi.py Outdated
# Winsock treats that exact value as a sentinel meaning "use a maximum
# reasonable backlog". So INT_MAX is the right value on every platform, though
# Windows honors it as that sentinel rather than as a tuned registry limit.
_LISTEN_BACKLOG = 2**31 - 1 # INT_MAX; the kernel caps this to the live somaxconn

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This inline comment says the kernel caps this to live somaxconn for every platform. Lines 69-73 say Windows uses the Winsock INT_MAX sentinel instead. Suggested fix: split the wording. Unix-like platforms clamp to live somaxconn, and Windows uses the Winsock sentinel.

…review)

Review feedback:
- The regression test asserted only `_LISTEN_BACKLOG > 65535`, which a future
  fixed ceiling like 1000000 would pass while violating the documented
  exactly-INT_MAX contract. Assert `_LISTEN_BACKLOG == 2**31 - 1` instead.
- The "kernel caps to live somaxconn" wording read as universal but only holds
  on Unix-like systems; Windows accepts INT_MAX via the Winsock SOMAXCONN
  sentinel, not a somaxconn clamp. Scope the wording accordingly in the inline
  comment, README, CHANGELOG, and AGENTS.md so it no longer contradicts the
  block comment's Windows note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@itg-karthicr

Copy link
Copy Markdown
Contributor Author

Both addressed in 5b30f5e.

Warning — test locks only > 65535. Good catch. The test now asserts _LISTEN_BACKLOG == 2**31 - 1, locking the exact contract. A future fixed ceiling like 1000000 would fail it, which is the point: the value must stay at INT_MAX, the largest backlog CPython's listen() accepts before OverflowError.

Info — clamp wording reads as universal. Fixed. The inline comment, README, CHANGELOG, and AGENTS now scope the somaxconn clamp to Unix-like systems and note Windows accepts INT_MAX via the Winsock SOMAXCONN sentinel, matching the block comment.

Full suite: 55 passing, ruff clean.

@itg-karthicr

Copy link
Copy Markdown
Contributor Author

Update: review feedback is resolved as of 5b30f5e, and the PR is ready to merge.

  • Test locks the exact contract: _LISTEN_BACKLOG == 2**31 - 1.
  • The somaxconn-clamp wording is scoped to Unix-like systems across the inline comment, README, CHANGELOG, and AGENTS; Windows is described as using the Winsock SOMAXCONN sentinel.

CI is green on all 8 checks (Lint, Package build, Documentation build, Python 3.9 through 3.13). Full suite: 55 passing, ruff clean. No open review threads remain.

@itg-karthicr itg-karthicr merged commit b4014a8 into master Jun 25, 2026
8 checks passed
@itg-karthicr itg-karthicr deleted the fix/somaxconn-listen-backlog branch June 25, 2026 03:17
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.

Complicated Determination Of SOMAXCONN

1 participant