Skip to content

Commit 0259d89

Browse files
Copilotrnovatorov
andcommitted
Add timeout handling for Docker operations
- Add 300-second timeout to docker pull in CI workflow - Implement pull_docker_image_with_timeout helper with proper timeout - Add better error handling for Docker daemon issues - Address code review feedback Co-authored-by: rnovatorov <20299819+rnovatorov@users.noreply.github.com>
1 parent 929a283 commit 0259d89

File tree

2 files changed

+49
-9
lines changed

2 files changed

+49
-9
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
run: make install-deps
2929

3030
- name: Pull Docker images for integration tests
31-
run: docker pull eclipse-mosquitto:latest
31+
run: timeout 300 docker pull eclipse-mosquitto:latest
3232

3333
- name: Run checks
3434
run: make check

tests/integration/conftest.py

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import enapter
1111

1212
MOSQUITTO_PORT = "1883/tcp"
13+
# Timeout for Docker image pull operations (in seconds)
14+
DOCKER_PULL_TIMEOUT = 300 # 5 minutes
1315

1416

1517
@pytest.fixture(name="enapter_mqtt_client")
@@ -40,14 +42,12 @@ def fixture_mosquitto_container(
4042
except docker.errors.ImageNotFound:
4143
# Pull the image if not available locally
4244
# This is handled by the CI workflow, but we keep it here for local testing
43-
try:
44-
docker_client.images.pull(image)
45-
except docker.errors.APIError as e:
46-
raise RuntimeError(
47-
f"Failed to pull Docker image {image}. "
48-
f"Please ensure Docker is running and you have network connectivity. "
49-
f"Error: {e}"
50-
) from e
45+
pull_docker_image_with_timeout(docker_client, image)
46+
except docker.errors.APIError as e:
47+
raise RuntimeError(
48+
f"Failed to access Docker daemon or image {image}. "
49+
f"Please ensure Docker is running. Error: {e}"
50+
) from e
5151

5252
try:
5353
old_mosquitto = docker_client.containers.get(name)
@@ -79,6 +79,46 @@ def random_unused_port() -> int:
7979
return addr[1]
8080

8181

82+
def pull_docker_image_with_timeout(
83+
docker_client: docker.DockerClient, image: str, timeout: int = DOCKER_PULL_TIMEOUT
84+
) -> None:
85+
"""Pull a Docker image with a timeout.
86+
87+
Args:
88+
docker_client: Docker client instance
89+
image: Image name to pull
90+
timeout: Timeout in seconds (default: DOCKER_PULL_TIMEOUT)
91+
92+
Raises:
93+
RuntimeError: If the image pull fails or times out
94+
TimeoutError: If the operation exceeds the timeout
95+
"""
96+
import concurrent.futures
97+
98+
def _pull_image() -> None:
99+
try:
100+
docker_client.images.pull(image)
101+
except docker.errors.APIError as e:
102+
raise RuntimeError(
103+
f"Failed to pull Docker image {image}. "
104+
f"Please ensure Docker is running and you have network connectivity. "
105+
f"Error: {e}"
106+
) from e
107+
108+
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
109+
future = executor.submit(_pull_image)
110+
try:
111+
future.result(timeout=timeout)
112+
except concurrent.futures.TimeoutError as e:
113+
raise TimeoutError(
114+
f"Timeout while pulling Docker image {image} after {timeout} seconds. "
115+
f"Please check your network connection or increase the timeout."
116+
) from e
117+
except Exception:
118+
# Re-raise any other exceptions from the pull operation
119+
raise
120+
121+
82122
@pytest.fixture(name="docker_client", scope="session")
83123
def fixture_docker_client() -> Generator[docker.DockerClient, None, None]:
84124
docker_client = docker.from_env()

0 commit comments

Comments
 (0)