From acfb464f60e5ccc31802351ceb99f6446b940dab Mon Sep 17 00:00:00 2001 From: Stavros Date: Wed, 2 Sep 2026 16:17:45 +0300 Subject: [PATCH 1/2] feat: add backoff to docker connection for proxies --- internal/service/docker_service.go | 64 ++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/internal/service/docker_service.go b/internal/service/docker_service.go index 21265a2e..214988b4 100644 --- a/internal/service/docker_service.go +++ b/internal/service/docker_service.go @@ -3,7 +3,10 @@ package service import ( "context" "fmt" + "os" + "time" + "github.com/cenkalti/backoff/v5" "github.com/steveiliop56/ding" "github.com/tinyauthapp/tinyauth/internal/model" "github.com/tinyauthapp/tinyauth/internal/utils/decoders" @@ -31,24 +34,42 @@ type DockerServiceInput struct { } func NewDockerService(i DockerServiceInput) (*DockerService, error) { - client, err := client.NewClientWithOpts(client.FromEnv) - if err != nil { - return nil, err + service := &DockerService{ + log: i.Log, + context: i.Ctx, } - client.NegotiateAPIVersion(i.Ctx) + service.log.App.Debug().Msg("Attempting to connect to Docker") - _, err = client.Ping(i.Ctx) + if os.Getenv("DOCKER_HOST") == "" { + cli, err := service.connect() + if err != nil { + return nil, fmt.Errorf("failed to connect to docker: %w", err) + } + service.client = cli + } else { + exp := backoff.NewExponentialBackOff() + exp.InitialInterval = 3 * time.Second + exp.RandomizationFactor = 0.1 + exp.Multiplier = 1.5 + exp.Reset() + + operation := func() (*client.Client, error) { + if service.client != nil { + service.client.Close() + } + cli, err := service.connect() + if err != nil { + return nil, err + } + return cli, nil + } - if err != nil { - i.Log.App.Debug().Err(err).Msg("Docker not connected") - return nil, nil - } + _, err := backoff.Retry(service.context, operation, backoff.WithBackOff(exp), backoff.WithMaxTries(3)) - service := &DockerService{ - log: i.Log, - client: client, - context: i.Ctx, + if err != nil { + return nil, fmt.Errorf("failed to connect to docker after retrying: %w", err) + } } service.isConnected = true @@ -59,6 +80,23 @@ func NewDockerService(i DockerServiceInput) (*DockerService, error) { return service, nil } +func (docker *DockerService) connect() (*client.Client, error) { + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + + if err != nil { + return nil, err + } + + _, err = cli.Ping(docker.context) + + if err != nil { + docker.log.App.Debug().Err(err).Msg("Docker not connected") + return nil, nil + } + + return cli, nil +} + func (docker *DockerService) getContainers() ([]container.Summary, error) { return docker.client.ContainerList(docker.context, container.ListOptions{}) } From 92ffb553af907a984effca8c530fb1fb75ab920b Mon Sep 17 00:00:00 2001 From: Stavros Date: Wed, 2 Sep 2026 16:36:48 +0300 Subject: [PATCH 2/2] fix: rabbit comments --- internal/service/docker_service.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/internal/service/docker_service.go b/internal/service/docker_service.go index 214988b4..28b12f8e 100644 --- a/internal/service/docker_service.go +++ b/internal/service/docker_service.go @@ -2,6 +2,7 @@ package service import ( "context" + "errors" "fmt" "os" "time" @@ -17,6 +18,10 @@ import ( "github.com/docker/docker/client" ) +var ( + ErrPingFailed = fmt.Errorf("failed to ping docker") +) + type DockerService struct { log *logger.Logger client *client.Client @@ -44,6 +49,10 @@ func NewDockerService(i DockerServiceInput) (*DockerService, error) { if os.Getenv("DOCKER_HOST") == "" { cli, err := service.connect() if err != nil { + if errors.Is(err, ErrPingFailed) { + service.log.App.Debug().Msg("Docker not connected") + return nil, nil + } return nil, fmt.Errorf("failed to connect to docker: %w", err) } service.client = cli @@ -65,11 +74,17 @@ func NewDockerService(i DockerServiceInput) (*DockerService, error) { return cli, nil } - _, err := backoff.Retry(service.context, operation, backoff.WithBackOff(exp), backoff.WithMaxTries(3)) + cli, err := backoff.Retry(service.context, operation, backoff.WithBackOff(exp), backoff.WithMaxTries(3)) if err != nil { + if errors.Is(err, ErrPingFailed) { + service.log.App.Debug().Msg("Docker not connected after retrying") + return nil, nil + } return nil, fmt.Errorf("failed to connect to docker after retrying: %w", err) } + + service.client = cli } service.isConnected = true @@ -90,8 +105,7 @@ func (docker *DockerService) connect() (*client.Client, error) { _, err = cli.Ping(docker.context) if err != nil { - docker.log.App.Debug().Err(err).Msg("Docker not connected") - return nil, nil + return nil, ErrPingFailed } return cli, nil