Skip to content

feat: Add wait strategy to check external (TCP) port availability#1495

Merged
HofmeisterAn merged 23 commits intotestcontainers:developfrom
WhiteTomX:develop
Aug 21, 2025
Merged

feat: Add wait strategy to check external (TCP) port availability#1495
HofmeisterAn merged 23 commits intotestcontainers:developfrom
WhiteTomX:develop

Conversation

@WhiteTomX
Copy link
Contributor

What does this PR do?

Using the TcpClient the new WaitStrategy allows to test if a port ist open from the host perspective.

Why is it important?

As discussed in #1350 it may be helpful to verify, that a Port is not only listening from inside the container but also from the host.

Related issues

How to test this PR

I added tests for the new waiting strategy. The only downside is, that one of the negative tests (that the wait fails when a port is not listening) fails on some of my systems as the proxy is listening on any mapped port. So you may get a error (for me with Rancher on Mac & Windows)

@netlify
Copy link

netlify bot commented Jul 28, 2025

Deploy Preview for testcontainers-dotnet ready!

Name Link
🔨 Latest commit 62caa85
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-dotnet/deploys/68a755ab9dfed900080e501d
😎 Deploy Preview https://deploy-preview-1495--testcontainers-dotnet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@WhiteTomX
Copy link
Contributor Author

Mmh, I just noticed, that testcontainers-java implemented this check in the general waitForHostPort Strategy.
Maybe this would be also a idea for us? Then it wouldn't be as bad, that the check from host doesn't work with some host configurations, as we would still have the Check from inside of the container.

Copy link
Collaborator

@HofmeisterAn HofmeisterAn left a comment

Choose a reason for hiding this comment

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

Mmh, I just noticed, that testcontainers-java implemented this check in the general waitForHostPort Strategy. Maybe this would be also a idea for us? Then it wouldn't be as bad, that the check from host doesn't work with some host configurations, as we would still have the Check from inside of the container.

Aligning with the other TC language implementations sounds good and is something we try to follow. I had a quick look, and I agree. It makes sense to follow both the internal and external listening checks. Ideally, we implement a new wait strategy (HostPortWaitStrategy) and mark the old one obsolete? WDYT?

@WhiteTomX
Copy link
Contributor Author

As the WaitStrategy for the internal Port depends on the ContainerOS I couldn't think of a way to have a WaitStrategy for both OS. So I implemented one class for now and let the WaitForContainerOS handle to choose the correct Internal Waiting Strategy.

I noticed that the current internal port waiting strategies only work with tcp (same for java implementation), so I decided to name the strategy to make that clear.

When we remove the internal only WaitingStrategies, we can refactor this without having duplicated code. Should I mark the existing UntilPortIsAvailable as obsolete?

Is there a way to output more specific errors in WaitStrategies? I forgot to map a port myself and needed to add debugging Console outputs until I figured that out :D

@HofmeisterAn
Copy link
Collaborator

HofmeisterAn commented Aug 4, 2025

As the WaitStrategy for the internal Port depends on the ContainerOS I couldn't think of a way to have a WaitStrategy for both OS.

You can pass the internal wait strategy, which depends on the OS, to the wait strategy using dependency injection:

/// <inheritdoc />
public override IWaitForContainerOS UntilPortIsAvailable(int port, Action<IWaitStrategy> waitStrategyModifier = null)
{
return AddCustomWaitStrategy(new UntilWindowsPortIsAvailable(port), waitStrategyModifier);
}

Is there a way to output more specific errors in WaitStrategies?

Throw an exception. Don't swallow the exception from GetMappedPublicPort(_containerPort). If the wait strategy is called, the port mapping should already be available. Otherwise, there is something wrong.

@WhiteTomX
Copy link
Contributor Author

Oh yea, it's my fault that the exception is gone🙈. That's fixed now!

I thought about using dependency injection to require a UntilPortIsAvailable specific to the OS. But that would require a new Interface/base class or just the "hope" that is the correct IWaitUntil that we get. That wouldn't be a reason not to do it. But additionally we would invoke the internal Wait check every time again when the external wait check fails and the Wait is retried. The implementation using them as separate waits would only retry the external wait.
I could implement a field to track if the internal check worked. But that feels weird, as it would be theoretically possible to invoke the method with different containers.

Should I implement it via constructor, another way or leave it like it is?

Copy link
Collaborator

@HofmeisterAn HofmeisterAn left a comment

Choose a reason for hiding this comment

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

Thanks for the adjustments, the PR looks good! I just have a quick question to make sure I've understood everything correctly.

UntilHostTcpPortAvailable(int) checks the remote connection (host to container), but not the internal connection (container to actual service), right?

we would invoke the internal Wait check every time again when the external wait check fails and the Wait is retried.

I was considering adding two wait strategies to the list. Once the first one succeeds, it will not run again. Something like:

return AddCustomWaitStrategy(new Internal...()).AddCustomWaitStrategy(new External...());

But this is probably unnecessary, and we can just rely on checking the remote connection.

@HofmeisterAn
Copy link
Collaborator

HofmeisterAn commented Aug 20, 2025

I'm also wondering if we should choose different names that are more meaningful and better describe what they check (mark the old one obsolete in IWaitForContainerOS).

Edit: Maybe something like UntilInternalTcpPortIsAvailable(int) and UntilExternalTcpPortIsAvailable(int) and then mark UntilPortIsAvailable(int) obsolete and refer users to the new APIs.

@HofmeisterAn HofmeisterAn changed the title Wait Until TcpConnected From Host feat: Add wait strategy to check external (TCP) port availability Aug 21, 2025
@HofmeisterAn HofmeisterAn added the enhancement New feature or request label Aug 21, 2025
Copy link
Collaborator

@HofmeisterAn HofmeisterAn left a comment

Choose a reason for hiding this comment

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

Thanks for the PR and your contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants