Skip to content

Mjcarroll/windows socket exhaustion - #1241

Open
mjcarroll wants to merge 5 commits into
rollingfrom
mjcarroll/windows_socket_exhaustion
Open

Mjcarroll/windows socket exhaustion#1241
mjcarroll wants to merge 5 commits into
rollingfrom
mjcarroll/windows_socket_exhaustion

Conversation

@mjcarroll

@mjcarroll mjcarroll commented Jun 5, 2026

Copy link
Copy Markdown
Member

Description

A few fixes to try to clear up Windows socket exhaustion issues.

Fixes #1229

ros2cli:

  • spawn_daemon returns early when a daemon is already running instead of racing to bind an address that is already taken.
  • Use SO_REUSEADDR for the daemon address check and for LocalXMLRPCServer on Windows too, so a socket in TIME_WAIT is not reported as busy.
  • Destroy the action client, action server and node in the local_node fixture, and shut down any daemon left behind by test_strategy, so tests stop leaking middleware sockets into the ones that follow.

ros2multicast — better reporting for #1141:

  • The receive thread only handled TimeoutError, so any other error became a pytest unhandled-thread-exception warning. test_api then failed as assert b'test_api' == None, which says nothing about the cause, and test_port_mismatch could pass even though the receive never happened. The error is now re-raised on the calling thread.
  • On Windows, test_group_mismatch fell through its conditional and discarded any OSError that was not 10051, so it passed. That is why it is absent from the failure list in Win 11 - ros2_multicast test_api regressions on release jobs #1141 while its three neighbours fail on the same error.
  • Multicast joins and UDP binds draw on resources shared by every process on the machine, so these tests fail when something unrelated exhausts them. On failure the tests now record the multicast membership count, the number of open UDP endpoints and the dynamic port range, which should make a CI log enough to tell an exhausted agent from a defect here.

Is this user-facing behavior change?

No

Did you use Generative AI?

Assissted-by: Antigravity CLI (Gemini 3.5 Flash)
Assisted-by: Claude Code (Opus 5)

Additional Information

The ros2multicast half does not fix #1141; it makes the next failure legible. Worth knowing while reading it: on Windows the UDP and TCP ephemeral pools are separate, and the UDP one defaults to 16384 ports from 49152. When it is exhausted, bind(('', 0)) fails with WSAENOBUFS (10055) and an implicit bind fails with WSAEINVAL (10022), while TCP bind/listen/connect keep working. A socket bound to a fixed port still binds and joins fine in that state, so the 10055 reported in #1141 — which comes from IP_ADD_MEMBERSHIP after a successful fixed-port bind — is not plain port exhaustion.

mjcarroll added 2 commits June 5, 2026 13:51
Try to cure windows socket exhaustion issues we are seeing in CI

Signed-off-by: Michael Carroll <mjcarroll.oss@gmail.com>
Signed-off-by: Michael Carroll <mjcarroll.oss@gmail.com>
@mjcarroll
mjcarroll marked this pull request as draft June 5, 2026 19:04
@mjcarroll mjcarroll self-assigned this Jun 5, 2026
…event socket exhaustion

Check if daemon is already running in spawn_daemon() before trying to bind. This preserves the single-daemon constraint while allowing allow_reuse_address to be True and enabling SO_REUSEADDR socket option on all platforms (including Windows). This fixes WSAEADDRINUSE / WinError 10055 socket exhaustion during TCP TIME_WAIT states.

Signed-off-by: Michael Carroll <mjcarroll.oss@gmail.com>
Assisted-by: Gemini CLI:Gemini 3.5 Flash [view_file, grep_search, list_dir, search_web, run_command, replace_file_content]
@mjcarroll
mjcarroll force-pushed the mjcarroll/windows_socket_exhaustion branch from 91681f8 to 0b73f57 Compare June 8, 2026 01:09

@fujitatomoya fujitatomoya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

fix looks good, but i am not 100% sure if this solves the problem for the windows...

starting CI to see if what is gonna happen 👀

@fujitatomoya

Copy link
Copy Markdown
Collaborator

Pulls: #1241
Gist: https://gist.githubusercontent.com/fujitatomoya/324ba7fba40e3b3d41f4cb589cfc8be5/raw/e543dce3b77ebe61c2292766d4fc87e5692a5f50/ros2.repos
BUILD args: --packages-above-and-dependencies ros2cli ros2multicast
TEST args: --packages-above ros2cli ros2multicast
ROS Distro: rolling
Job: ci_launcher
ci_launcher ran: https://ci.ros2.org/job/ci_launcher/19500

  • Linux Build Status
  • Linux-aarch64 Build Status
  • Linux-rhel Build Status
  • Windows Build Status

@mjcarroll

Copy link
Copy Markdown
Member Author

fix looks good, but i am not 100% sure if this solves the problem for the windows...

starting CI to see if what is gonna happen 👀

Yeah, at this point I'm kind of just attempting things to see if it makes a difference. It does seem that the real underlying cause is that we are running out of sockets on Windows. Based on my reading, sockets will still live for a few minutes after a process terminates, so I'm experimenting with more aggressively cleaning them up before we shutdown.

The added teardown blocks in the daemon/strategy test fixtures left
only one blank line before the following top-level def/decorator
instead of the required two.
The receive thread only handled TimeoutError, so any other error became a
pytest unhandled-thread-exception warning. test_api then failed as
"assert b'test_api' == None", which says nothing about the actual cause,
and test_port_mismatch could pass despite the receive never happening.
Stash the error and re-raise it on the calling thread instead.

Multicast joins and UDP binds draw on resources that are shared by every
process on the machine, so these tests fail when something unrelated has
exhausted them. Record the membership count, the number of open UDP
endpoints, and the dynamic port range alongside the failure so a CI log is
enough to tell an exhausted machine from a defect here.

Also re-raise in test_group_mismatch. On Windows any OSError that was not
10051 fell through the conditional and was discarded, so the test passed
while hiding the same failure its neighbours report.

Refs: #1141
@mjcarroll
mjcarroll marked this pull request as ready for review September 3, 2026 22:10
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.

🧑‍🌾 ros2cli_daemon tests failing in win rel because it can't spawn daemons Win 11 - ros2_multicast test_api regressions on release jobs

2 participants