Skip to content

Publish test containers on host ports below the ephemeral range - #1920

Draft
realtonyyoung wants to merge 7 commits into
mainfrom
container-host-ports
Draft

realtonyyoung wants to merge 7 commits into
mainfrom
container-host-ports

Conversation

@realtonyyoung

@realtonyyoung realtonyyoung commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

AI-4381 (no GitHub issue)

What & why

The integration tests' WorkOS emulator took its host port from a port-0 bind, and Testcontainers' resource reaper took Docker's choice. Both draw from 32768–60999, the Linux ephemeral range a loaded runner's outbound sockets and TIME_WAITs crowd, so a start can fail with address already in use however often it is retried there. Every container now publishes on a port from 20000–32767 that is checked free on IPv4 and IPv6 first, picked by a process-wide cursor so two starts in one process never race for the same one, and a clash with another process, in either of Docker's two wordings, rebuilds the container on the next free port. The emulator's image is also built from new DockerImage(repository, tag:), since Testcontainers parses an image string with a regex whose 5-second timeout a starved runner can exceed. This is the twin of kurrent-io/kcap-server#2654

Where to look

ContainerHostPorts in the integration project. The reaper's port goes through TestcontainersSettings.ResourceReaperPublicHostPort, which is marked obsolete but still read by Testcontainers 4.16; its test fails if an upgrade stops honouring it. Two unit guards refuse any WithPortBinding not fed by the picker and any container built from an image string

Verification

Test Broken to see it red First failing line
a full cycle of picks never hands out a held port free check bypassed Expected to not contain 22575
the emulator and the reaper publish below 32768 (real container) emulator on a port-0 bind Expected to be less than 32768 but received 53312
the same, reaper alone reaper left on Docker's port … but received 53386
no test publishes on Docker's choice (unit guard) main's WorkOSEmulator.cs collection contains items: [test/Capacitor.Cli.Tests.Integration/WorkOSEmulator.cs]
a port held on IPv6 alone is passed over IPv4-only free check Expected to not be equal … but received 30834
"port is already allocated" is a clash kernel wording only Expected to be equal to True but received False
an unbound KurrentDB/Postgres builder, offset or target-typed, is flagged (unit guard) binding check alone three rows fail
no test builds a container from an image string (unit guard) the emulator's "ghcr.io/workos/emulate:0.15.0" collection contains items: [test/Capacitor.Cli.Tests.Integration/WorkOSEmulator.cs]

WorkOSEmulatorSignInTests (login, refresh and restart against the emulator) passes on the new port

🤖 Generated with Claude Code

A port-0 bind and Docker's own choice both draw from 32768-60999, which a loaded runner's sockets
fill. The resource reaper's port setting is marked obsolete but still read, and its test fails if
an upgrade stops honouring it.

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

coderabbitai Bot commented Oct 24, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

realtonyyoung and others added 6 commits October 24, 2026 14:37
Testcontainers parses an image string with a regex whose 5-second timeout a starved runner can
exceed; only new DockerImage(repository, tag: ...) skips the parse.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two processes picking the same port get Docker's own "port is already allocated", not the
kernel's "address already in use".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tement

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A quote inside a comment opened a string that hid the code after it, and a lambda body's semicolon cut a builder chain short.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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