Commit
fd3c0b8 (Add optional Gemma 4 image support (#144)). Both constants involved are unchanged since e65da9e.
Mac hardware and memory
Apple M3 Pro, 18 GB
macOS and Swift versions
macOS 27.0 (26A5416b), Swift 6.4 (swiftlang-6.4.0.27.1)
Does this require the installed model?
No.
Reproduction steps
for i in $(seq 1 20); do Scripts/test.sh --filter connectionsBeyondTheCapAreClosed; done
Expected behavior
The test passes on every run.
Observed behavior
It fails 17 of 20 runs on this machine:
✘ Test connectionsBeyondTheCapAreClosed() recorded an issue at
ServerIngressHardeningTests.swift:301:6: Caught error: .systemCall("connect", 54)
54 is ECONNRESET, thrown by connectedSocket (Tests/TurboFieldfareServer/HTTPServerTests.swift:907) when the blocking Darwin.connect fails.
It passes on GitHub Actions, so it shows up as a test that is green in CI and mostly red locally rather than as an obvious break.
Cause
Two values disagree:
connectionsBeyondTheCapAreClosed opens TurboFieldfareHTTPServer.maximumConnections = 128 sockets in a tight synchronous loop, before it waits for the accept loop at all.
TurboFieldfareHTTPServer.start sets .serverChannelOption(ChannelOptions.backlog, value: 16) (Sources/TurboFieldfareServer/Core/HTTPServer.swift:59).
So the test can need up to 128 connections sitting in the listen queue while NIO's accept loop is still draining it, but the queue holds 16. Once it is full, Darwin answers further SYNs with RST rather than queueing them, and the blocking connect() returns ECONNRESET. Whether the accept loop stays ahead of the test's loop is a race, which is why the failure is intermittent rather than constant.
Confirming experiment
Changing only that one line to value: 256 and re-running the same 20 iterations:
ChannelOptions.backlog |
passes |
| 16 (current) |
3 / 20 |
| 256 |
20 / 20 |
Nothing else was changed, and the line was reverted afterwards.
Possible directions
Not sending a patch, because the right fix depends on what the backlog of 16 is for:
- If 16 is deliberate, the test is asserting something the server does not promise. It could pace its connects, or tolerate and retry
ECONNRESET while filling up to the cap.
- If 16 is incidental, it looks low for a server whose own connection cap is 128 — a real client burst would meet the same RST.
kern.ipc.somaxconn is 128 on this machine, so a backlog of 128 would be accepted as requested.
I have not measured whether a backlog of 16 causes trouble for real clients. The only thing established here is that it is what makes this test unstable.
Commit
fd3c0b8(Add optional Gemma 4 image support (#144)). Both constants involved are unchanged sincee65da9e.Mac hardware and memory
Apple M3 Pro, 18 GB
macOS and Swift versions
macOS 27.0 (26A5416b), Swift 6.4 (swiftlang-6.4.0.27.1)
Does this require the installed model?
No.
Reproduction steps
Expected behavior
The test passes on every run.
Observed behavior
It fails 17 of 20 runs on this machine:
54 is
ECONNRESET, thrown byconnectedSocket(Tests/TurboFieldfareServer/HTTPServerTests.swift:907) when the blockingDarwin.connectfails.It passes on GitHub Actions, so it shows up as a test that is green in CI and mostly red locally rather than as an obvious break.
Cause
Two values disagree:
connectionsBeyondTheCapAreClosedopensTurboFieldfareHTTPServer.maximumConnections= 128 sockets in a tight synchronous loop, before it waits for the accept loop at all.TurboFieldfareHTTPServer.startsets.serverChannelOption(ChannelOptions.backlog, value: 16)(Sources/TurboFieldfareServer/Core/HTTPServer.swift:59).So the test can need up to 128 connections sitting in the listen queue while NIO's accept loop is still draining it, but the queue holds 16. Once it is full, Darwin answers further SYNs with RST rather than queueing them, and the blocking
connect()returnsECONNRESET. Whether the accept loop stays ahead of the test's loop is a race, which is why the failure is intermittent rather than constant.Confirming experiment
Changing only that one line to
value: 256and re-running the same 20 iterations:ChannelOptions.backlogNothing else was changed, and the line was reverted afterwards.
Possible directions
Not sending a patch, because the right fix depends on what the backlog of 16 is for:
ECONNRESETwhile filling up to the cap.kern.ipc.somaxconnis 128 on this machine, so a backlog of 128 would be accepted as requested.I have not measured whether a backlog of 16 causes trouble for real clients. The only thing established here is that it is what makes this test unstable.