Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions docs/features/wait_strategies.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,17 @@ Testcontainers-Python provides several strategies to wait for containers to be r

## Basic Wait Strategy

The simplest way to wait for a container is using the `wait_container_is_ready` decorator:
The simplest way to wait for a container is using a structured wait strategy:

```python
from testcontainers.core.waiting_utils import wait_container_is_ready
from testcontainers.core.wait_strategies import HttpWaitStrategy

class MyContainer(DockerContainer):
@wait_container_is_ready()
def _connect(self):
# Your connection logic here
pass
HttpWaitStrategy(8080).wait_until_ready(self)
```

This decorator will retry the method until it succeeds or times out. By default, it will retry for 120 seconds with a 1-second interval between attempts.
The strategy will retry until it succeeds or times out. By default, it will retry for 120 seconds with a 1-second interval between attempts.

## Log-based Waiting

Expand Down
18 changes: 3 additions & 15 deletions modules/generic/testcontainers/generic/server.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
from typing import Union
from urllib.error import HTTPError, URLError
from urllib.request import urlopen

import httpx

from testcontainers.core.container import DockerContainer
from testcontainers.core.exceptions import ContainerStartException
from testcontainers.core.image import DockerImage
from testcontainers.core.waiting_utils import wait_container_is_ready
from testcontainers.core.wait_strategies import HttpWaitStrategy


class ServerContainer(DockerContainer):
Expand Down Expand Up @@ -40,19 +38,9 @@ def __init__(self, port: int, image: Union[str, DockerImage]) -> None:
self.internal_port = port
self.with_exposed_ports(self.internal_port)

@wait_container_is_ready(HTTPError, URLError)
def _connect(self) -> None:
# noinspection HttpUrlsUsage
url = self._create_connection_url()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not sure skipping the _create_connection_url is a good idea

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jmillxyz wdyt?

Copy link
Copy Markdown
Contributor

@Tranquility2 Tranquility2 Apr 1, 2026

Choose a reason for hiding this comment

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

Notice it has some logic

def _create_connection_url(self) -> str:
        if self._container is None:
            raise ContainerStartException("container has not been started")
        host = self.get_container_host_ip()
        exposed_port = self.get_exposed_port(self.internal_port)
        url = f"http://{host}:{exposed_port}"
        return url

try:
with urlopen(url) as r:
assert b"" in r.read()
except HTTPError as e:
# 404 is expected, as the server may not have the specific endpoint we are looking for
if e.code == 404:
pass
else:
raise
strategy = HttpWaitStrategy(self.internal_port).for_status_code(404)
strategy.wait_until_ready(self)

def get_api_url(self) -> str:
raise NotImplementedError
Expand Down
Loading