Compare commits

...
2 Commits
Author SHA1 Message Date
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
b61fc6b54e chore(deps): bump the minor-patch group across 1 directory with 3 updates (#1116)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-03 12:15:04 +03:00
StavrosandGitHub bbcc8cafa6 feat: add backoff to docker connection for proxies (#1114) 2026-09-03 12:14:30 +03:00
3 changed files with 93 additions and 41 deletions
+3 -3
View File
@@ -26,19 +26,19 @@
"i18next": "^26.4.0", "i18next": "^26.4.0",
"i18next-browser-languagedetector": "^8.2.1", "i18next-browser-languagedetector": "^8.2.1",
"i18next-resources-to-backend": "^1.2.3", "i18next-resources-to-backend": "^1.2.3",
"lucide-react": "^1.37.0", "lucide-react": "^1.38.0",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"radix-ui": "^1.6.7", "radix-ui": "^1.6.7",
"react": "^19.2.8", "react": "^19.2.8",
"react-dom": "^19.2.8", "react-dom": "^19.2.8",
"react-hook-form": "^7.86.0", "react-hook-form": "^7.87.0",
"react-i18next": "^17.0.12", "react-i18next": "^17.0.12",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
"react-router": "^8.3.1", "react-router": "^8.3.1",
"sonner": "^2.0.8", "sonner": "^2.0.8",
"tailwind-merge": "^3.5.0", "tailwind-merge": "^3.5.0",
"tailwindcss": "^4.3.3", "tailwindcss": "^4.3.3",
"zod": "^4.5.2" "zod": "^4.5.4"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",
+23 -23
View File
@@ -10,7 +10,7 @@ importers:
dependencies: dependencies:
'@hookform/resolvers': '@hookform/resolvers':
specifier: ^5.9.1 specifier: ^5.9.1
version: 5.9.1(react-hook-form@7.86.0(react@19.2.8))(zod@4.5.2) version: 5.9.1(react-hook-form@7.87.0(react@19.2.8))(zod@4.5.4)
'@radix-ui/react-dropdown-menu': '@radix-ui/react-dropdown-menu':
specifier: ^2.1.24 specifier: ^2.1.24
version: 2.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) version: 2.1.24(@types/react-dom@19.2.5(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@@ -51,8 +51,8 @@ importers:
specifier: ^1.2.3 specifier: ^1.2.3
version: 1.2.3 version: 1.2.3
lucide-react: lucide-react:
specifier: ^1.37.0 specifier: ^1.38.0
version: 1.37.0(react@19.2.8) version: 1.38.0(react@19.2.8)
next-themes: next-themes:
specifier: ^0.4.6 specifier: ^0.4.6
version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8) version: 0.4.6(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
@@ -66,8 +66,8 @@ importers:
specifier: ^19.2.8 specifier: ^19.2.8
version: 19.2.8(react@19.2.8) version: 19.2.8(react@19.2.8)
react-hook-form: react-hook-form:
specifier: ^7.86.0 specifier: ^7.87.0
version: 7.86.0(react@19.2.8) version: 7.87.0(react@19.2.8)
react-i18next: react-i18next:
specifier: ^17.0.12 specifier: ^17.0.12
version: 17.0.12(i18next@26.4.0(typescript@6.0.3))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@6.0.3) version: 17.0.12(i18next@26.4.0(typescript@6.0.3))(react-dom@19.2.8(react@19.2.8))(react@19.2.8)(typescript@6.0.3)
@@ -87,8 +87,8 @@ importers:
specifier: ^4.3.3 specifier: ^4.3.3
version: 4.3.3 version: 4.3.3
zod: zod:
specifier: ^4.5.2 specifier: ^4.5.4
version: 4.5.2 version: 4.5.4
devDependencies: devDependencies:
'@eslint/js': '@eslint/js':
specifier: ^10.0.1 specifier: ^10.0.1
@@ -2053,8 +2053,8 @@ packages:
lru-cache@5.1.1: lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
lucide-react@1.37.0: lucide-react@1.38.0:
resolution: {integrity: sha512-LPsB4rD1TD6wZu1djKOf9vUnS1jTNaHbolXebXDgiTdb6jeA1agIJhJsIybCmjKmQClcOaal1o1OaiYahEftyQ==} resolution: {integrity: sha512-xZCyBd/wiVUDactoCc+42TjL0aB7EBOXsuX+tjz+W/sGzw2KhHpL1NOH3FIaVUcpimvUBpIYfz34Ofj9S5JEzQ==}
peerDependencies: peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
@@ -2263,8 +2263,8 @@ packages:
peerDependencies: peerDependencies:
react: ^19.2.8 react: ^19.2.8
react-hook-form@7.86.0: react-hook-form@7.87.0:
resolution: {integrity: sha512-4kbWJrh5jPZt1+YqVcXcGKffGcXV/XVbozknLh0Yjh0KhpoAkus21TAQhzRYqNwFkkObmnSvRlZZ3GT+ehoIrA==} resolution: {integrity: sha512-zhFzWvLxNHH+8839OnZcUxgMZw88ah2jZWDWvKWgF3Tpbnd0vKL+dlcuU3nZVWESZQjd81EW8K+wU+cYfYAc0w==}
engines: {node: '>=18.0.0'} engines: {node: '>=18.0.0'}
peerDependencies: peerDependencies:
react: ^16.8.0 || ^17 || ^18 || ^19 react: ^16.8.0 || ^17 || ^18 || ^19
@@ -2619,8 +2619,8 @@ packages:
peerDependencies: peerDependencies:
zod: ^3.25.0 || ^4.0.0 zod: ^3.25.0 || ^4.0.0
zod@4.5.2: zod@4.5.4:
resolution: {integrity: sha512-XkYXCol10+ba/6F/cueWV+TezUeOqXW0hdeJt5CdXjTYeAgAQg5N03RQdJ80mhfFE72+pblvYMW4wy2Qp4Qbrg==} resolution: {integrity: sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==}
zwitch@2.0.4: zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
@@ -2782,12 +2782,12 @@ snapshots:
'@floating-ui/utils@0.2.12': {} '@floating-ui/utils@0.2.12': {}
'@hookform/resolvers@5.9.1(react-hook-form@7.86.0(react@19.2.8))(zod@4.5.2)': '@hookform/resolvers@5.9.1(react-hook-form@7.87.0(react@19.2.8))(zod@4.5.4)':
dependencies: dependencies:
'@standard-schema/utils': 0.3.0 '@standard-schema/utils': 0.3.0
react-hook-form: 7.86.0(react@19.2.8) react-hook-form: 7.87.0(react@19.2.8)
optionalDependencies: optionalDependencies:
zod: 4.5.2 zod: 4.5.4
'@humanfs/core@0.19.2': '@humanfs/core@0.19.2':
dependencies: dependencies:
@@ -4023,8 +4023,8 @@ snapshots:
'@babel/parser': 7.29.3 '@babel/parser': 7.29.3
eslint: 10.9.1(jiti@2.7.0) eslint: 10.9.1(jiti@2.7.0)
hermes-parser: 0.25.1 hermes-parser: 0.25.1
zod: 4.5.2 zod: 4.5.4
zod-validation-error: 4.0.2(zod@4.5.2) zod-validation-error: 4.0.2(zod@4.5.4)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -4414,7 +4414,7 @@ snapshots:
dependencies: dependencies:
yallist: 3.1.1 yallist: 3.1.1
lucide-react@1.37.0(react@19.2.8): lucide-react@1.38.0(react@19.2.8):
dependencies: dependencies:
react: 19.2.8 react: 19.2.8
@@ -4799,7 +4799,7 @@ snapshots:
react: 19.2.8 react: 19.2.8
scheduler: 0.27.0 scheduler: 0.27.0
react-hook-form@7.86.0(react@19.2.8): react-hook-form@7.87.0(react@19.2.8):
dependencies: dependencies:
react: 19.2.8 react: 19.2.8
@@ -5130,10 +5130,10 @@ snapshots:
yocto-queue@0.1.0: {} yocto-queue@0.1.0: {}
zod-validation-error@4.0.2(zod@4.5.2): zod-validation-error@4.0.2(zod@4.5.4):
dependencies: dependencies:
zod: 4.5.2 zod: 4.5.4
zod@4.5.2: {} zod@4.5.4: {}
zwitch@2.0.4: {} zwitch@2.0.4: {}
+67 -15
View File
@@ -2,8 +2,12 @@ package service
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"os"
"time"
"github.com/cenkalti/backoff/v5"
"github.com/steveiliop56/ding" "github.com/steveiliop56/ding"
"github.com/tinyauthapp/tinyauth/internal/model" "github.com/tinyauthapp/tinyauth/internal/model"
"github.com/tinyauthapp/tinyauth/internal/utils/decoders" "github.com/tinyauthapp/tinyauth/internal/utils/decoders"
@@ -14,6 +18,10 @@ import (
"github.com/docker/docker/client" "github.com/docker/docker/client"
) )
var (
ErrPingFailed = fmt.Errorf("failed to ping docker")
)
type DockerService struct { type DockerService struct {
log *logger.Logger log *logger.Logger
client *client.Client client *client.Client
@@ -31,26 +39,54 @@ type DockerServiceInput struct {
} }
func NewDockerService(i DockerServiceInput) (*DockerService, error) { func NewDockerService(i DockerServiceInput) (*DockerService, error) {
client, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
return nil, err
}
client.NegotiateAPIVersion(i.Ctx)
_, err = client.Ping(i.Ctx)
if err != nil {
i.Log.App.Debug().Err(err).Msg("Docker not connected")
return nil, nil
}
service := &DockerService{ service := &DockerService{
log: i.Log, log: i.Log,
client: client,
context: i.Ctx, context: i.Ctx,
} }
service.log.App.Debug().Msg("Attempting to connect to Docker")
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
} 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
}
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 service.isConnected = true
service.log.App.Debug().Msg("Docker connected successfully") service.log.App.Debug().Msg("Docker connected successfully")
@@ -59,6 +95,22 @@ func NewDockerService(i DockerServiceInput) (*DockerService, error) {
return service, nil 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 {
return nil, ErrPingFailed
}
return cli, nil
}
func (docker *DockerService) getContainers() ([]container.Summary, error) { func (docker *DockerService) getContainers() ([]container.Summary, error) {
return docker.client.ContainerList(docker.context, container.ListOptions{}) return docker.client.ContainerList(docker.context, container.ListOptions{})
} }