Skip to content

Add a max_connections limit - #11

Open
lpgauth wants to merge 3 commits into
masterfrom
max-connections
Open

lpgauth wants to merge 3 commits into
masterfrom
max-connections

Conversation

@lpgauth

@lpgauth lpgauth commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Caps concurrent connections served across all listeners with a new max_connections config key. Default is infinity, so existing behaviour is unchanged.

  • The acceptor claims a slot from a shared atomics counter right after accept, before the worker is spawned; the worker releases it from a try/after, so an abnormal exit still gives the slot back and the count cannot drift upwards.
  • Over the limit, the accepted socket is closed immediately without a response. Writing one from the accept loop would stall every pending accept behind a slow client.
  • Rejections emit [whitecap, connections, max_connections]; [whitecap, connections, accept] now fires only for connections handed to a worker.
  • whitecap:connections/0 returns the current count.
  • infinity short-circuits in both the acceptor and the connection worker, so the default configuration does no counter work on the hot path.

The limit is VM-wide rather than per-listener, matching how max_keepalive and the timeouts are already configured.

Test plan

New test/whitecap_max_connections_tests.erl covers the N+1th connection being closed unanswered, a closed connection freeing its slot, and a crashing handler's worker freeing its slot. compile (warnings-as-errors), xref, eunit (35 tests) and dialyzer pass locally.

CHANGELOG and app vsn are left for the release commit.

Cap the number of concurrent connections served across all listeners
with a new `max_connections` config key (default `infinity`, so the
existing behaviour is unchanged).

The acceptor claims a slot from a shared atomics counter right after
accept, before the worker is spawned, and the worker releases it from a
try/after so an abnormal exit still gives the slot back and the count
cannot drift upwards. Over the limit the accepted socket is closed
immediately without a response: a send from the accept loop would stall
every pending accept behind one slow client. Rejections emit
`[whitecap, connections, max_connections]`, and `whitecap:connections/0`
returns the current count.

`infinity` short-circuits in both the acceptor and the connection
worker, so the default configuration does no counter work on the hot
path.
counters has no add-and-get, so the check read the counter back after
incrementing it and two acceptors could each see a value under the limit
for the same slot. atomics:add_get/3 returns the post-increment value in
one atomic op, making the limit exact and dropping an op from the accept
path.
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.

1 participant