Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docker_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,17 @@ func (c *DockerClient) Info(ctx context.Context, options client.InfoOptions) (cl
infoLabels += infoLabelsSb72.String()
}

host, err := core.ExtractDockerHost(ctx)
if err != nil {
return dockerInfo, err
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
log.Printf(infoMessage, packagePath,
dockerInfo.Info.ServerVersion,
c.ClientVersion(),
dockerInfo.Info.OperatingSystem, dockerInfo.Info.MemTotal/1024/1024,
infoLabels,
internal.Version,
core.MustExtractDockerHost(ctx),
host,
core.MustExtractDockerSocket(ctx),
core.SessionID(),
core.ProcessID(),
Expand Down
7 changes: 5 additions & 2 deletions internal/core/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ import (

// NewClient returns a new docker client extracting the docker host from the different alternatives
func NewClient(ctx context.Context, ops ...client.Opt) (*client.Client, error) {
tcConfig := config.Read()
dockerHost, err := ExtractDockerHost(ctx)
if err != nil {
return nil, err
}

dockerHost := MustExtractDockerHost(ctx)
tcConfig := config.Read()

opts := []client.Opt{client.FromEnv}
if dockerHost != "" {
Expand Down
23 changes: 13 additions & 10 deletions internal/core/docker_host.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ var (
)

var (
dockerHostCache string
dockerHostOnce sync.Once
dockerHostCache string
dockerHostErrCache error
dockerHostOnce sync.Once
)

var (
Expand Down Expand Up @@ -85,16 +86,18 @@ var dockerHostCheck = func(ctx context.Context, host string) error {
// 6. Rootless docker socket path.
// 7. Else, because the Docker host is not set, it panics.
func MustExtractDockerHost(ctx context.Context) string {
dockerHostOnce.Do(func() {
cache, err := extractDockerHost(ctx)
if err != nil {
panic(err)
}
host, err := ExtractDockerHost(ctx)
if err != nil {
panic(err)
}
return host
}

dockerHostCache = cache
func ExtractDockerHost(ctx context.Context) (string, error) {
dockerHostOnce.Do(func() {
dockerHostCache, dockerHostErrCache = extractDockerHost(ctx)
})

return dockerHostCache
return dockerHostCache, dockerHostErrCache
}
Comment on lines +96 to 101
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not cache Docker host extraction errors process-wide.

At Line 97, sync.Once stores the first failure forever (dockerHostErrCache). A transient startup failure becomes unrecoverable for the lifetime of the process, even if Docker/environment is fixed later.

Suggested fix (cache success only, allow retry on errors)
 var (
-	dockerHostCache    string
-	dockerHostErrCache error
-	dockerHostOnce     sync.Once
+	dockerHostCache  string
+	dockerHostCached bool
+	dockerHostMu     sync.Mutex
 )
@@
 func ExtractDockerHost(ctx context.Context) (string, error) {
-	dockerHostOnce.Do(func() {
-		dockerHostCache, dockerHostErrCache = extractDockerHost(ctx)
-	})
-	return dockerHostCache, dockerHostErrCache
+	dockerHostMu.Lock()
+	defer dockerHostMu.Unlock()
+
+	if dockerHostCached {
+		return dockerHostCache, nil
+	}
+
+	host, err := extractDockerHost(ctx)
+	if err != nil {
+		return "", err
+	}
+
+	dockerHostCache = host
+	dockerHostCached = true
+	return dockerHostCache, nil
 }

Also applies to: 34-36

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/core/docker_host.go` around lines 96 - 101, The code uses
dockerHostOnce to cache both success and failure in ExtractDockerHost, causing
dockerHostErrCache to be sticky; change the logic so dockerHostOnce (and
dockerHostCache) only records on successful extraction: call extractDockerHost
inside a retryable path and only assign to dockerHostCache and mark
initialization (or call dockerHostOnce.Do) when extractDockerHost returns nil
error; if extractDockerHost returns an error, return it directly without setting
dockerHostErrCache so future calls can retry. Update the related variables
dockerHostOnce, dockerHostCache, dockerHostErrCache and the call site of
extractDockerHost to follow this pattern.


// MustExtractDockerSocket Extracts the docker socket from the different alternatives, removing the socket schema and
Expand Down
7 changes: 5 additions & 2 deletions provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,18 @@ func NewDockerProvider(provOpts ...DockerProviderOption) (*DockerProvider, error
}

ctx := context.Background()
host, err := core.ExtractDockerHost(ctx)
if err != nil {
return nil, err
}
c, err := NewDockerClientWithOpts(ctx)
if err != nil {
return nil, err
}

return &DockerProvider{
DockerProviderOptions: o,
host: core.MustExtractDockerHost(ctx),
client: c,
host: host,
config: config.Read(),
}, nil
}
Loading