Skip to content

[Enhancement]: Retry transient Docker image pull failures #1733

Description

@thomhurst

Problem

Testcontainers for .NET currently performs a single image pull attempt. A transient registry or network failure therefore aborts the container startup and the entire test session, even when an immediate retry would succeed.

We observed this in a GitHub Actions job using Testcontainers 4.7.0, Docker on ubuntu-latest, and redis:7-alpine:

Docker API responded with status code=InternalServerError,
response={"message":"Head \"https://registry-1.docker.io/v2/library/redis/manifests/7-alpine\": ... read: connection reset by peer"}

Failed run: https://github.com/thomhurst/Respire/actions/runs/31280152764/attempts/1

Re-running only the failed job passed without any source change. Because container initialization was shared for the test session, this single transient pull failure caused all five authentication tests to fail before execution.

Current develop appears to call the image creation operation once without a retry:

Solution

Add a bounded retry policy around image pulls for clearly transient failures, while honoring the supplied cancellation token.

A possible default policy:

  • retry a small number of times, such as three attempts;
  • use exponential backoff with jitter;
  • retry transport failures, timeouts, HTTP 408/429, and Docker API 5xx responses;
  • honor Retry-After where available;
  • do not retry permanent failures such as invalid image names, authentication/authorization failures, or missing manifests;
  • log each retry with the image name, attempt, delay, and sanitized failure reason.

Making the policy configurable would be useful, but a conservative built-in default would address the common CI failure mode.

Benefit

This would reduce flaky integration-test failures caused by short-lived Docker Hub, registry-auth, proxy, DNS, or network interruptions. It also keeps retry behavior consistent across CI systems instead of requiring every Testcontainers consumer to wrap container startup or pre-pull images independently.

Alternatives

  • Pre-pull images in CI with a shell-level retry loop.
  • Cache required images on self-hosted runners.
  • Wrap StartAsync in application code, although this retries more than the image pull and can repeat container/resource setup.
  • Leave retries entirely to Docker Engine; in this case Docker returned the transient registry error immediately, so no effective retry occurred.

Would you like to help contributing this enhancement?

Yes

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions