From a89d3a3b64e698f07a4c29d49211a253da8ace29 Mon Sep 17 00:00:00 2001 From: Golo Roden Date: Sat, 1 Aug 2026 10:48:21 +0200 Subject: [PATCH] fix: pull the container image only once per process Container.start() pulled the image from the registry on every single call. Since each test gets its own container, a full test run made 77 registry round trips for an image that was already local -- 91 of 156 seconds, 58% of the total runtime. That also made the suite flaky. Pull latency is normally ~1.1s, but outliers of up to 15.5s showed up in two of four measured runs, and pytest allows 30s for setup, test and teardown combined. Two runs failed with a setup time of exactly 30.01s, hitting different tests each time. Docker Hub allows 100 anonymous requests per hour and source IP, so a single run already consumes 77% of that budget. Remember which images were pulled in this process, so the first start pulls and every later one reuses the local image. Runtime drops from ~156s to ~64s, and the slowest setup from 15.78s to 1.84s. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01F3ADPwk11GHQF7BBwQHaPz --- eventsourcingdb/container.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/eventsourcingdb/container.py b/eventsourcingdb/container.py index 3be6b9b..484b9b9 100644 --- a/eventsourcingdb/container.py +++ b/eventsourcingdb/container.py @@ -3,6 +3,7 @@ import tarfile import time from http import HTTPStatus +from typing import ClassVar import docker import requests @@ -16,6 +17,10 @@ class Container: + # Images already pulled in this process. Every container start would + # otherwise hit the registry again, even though the image is local. + _pulled_images: ClassVar[set[str]] = set() + def __init__( self, ) -> None: @@ -191,11 +196,18 @@ def start(self) -> "Container": return self def _pull_or_get_image(self) -> None: + image = f"{self._image_name}:{self._image_tag}" + + if image in Container._pulled_images: + return + try: self._docker_client.images.pull(self._image_name, self._image_tag) except errors.APIError as e: self._handle_image_pull_error(e) + Container._pulled_images.add(image) + def _handle_image_pull_error(self, error) -> None: image_name = f"{self._image_name}:{self._image_tag}" try: