diff --git a/pkg/ipc/listener_windows.go b/pkg/ipc/listener_windows.go index f55ae460233..bf12b04ecaa 100644 --- a/pkg/ipc/listener_windows.go +++ b/pkg/ipc/listener_windows.go @@ -11,6 +11,7 @@ import ( "net" "os/user" "strings" + "time" "golang.org/x/sys/windows" @@ -35,11 +36,26 @@ func CreateListener(log *logger.Logger, address string) (net.Listener, error) { if err != nil { return nil, fmt.Errorf("failed to create security descriptor: %w", err) } - lis, err := npipe.NewListener(npipe.TransformString(address), sd) - if err != nil { - return nil, fmt.Errorf("failed to create npipe listener: %w", err) + + retryDuration := 5 * time.Second + backoffDelay := 200 * time.Millisecond + + deadline := time.Now().Add(retryDuration) + var lastErr error + + for time.Now().Before(deadline) { + lis, err := npipe.NewListener(npipe.TransformString(address), sd) + if err == nil { + return lis, nil + } + + // Log and backoff before retrying + log.Warnf("failed to create npipe listener, retrying...: %v", err) + lastErr = err + time.Sleep(backoffDelay) } - return lis, nil + + return nil, fmt.Errorf("failed to create npipe listener after retries: %w", lastErr) } func CleanupListener(log *logger.Logger, address string) { diff --git a/pkg/ipc/listener_windows_test.go b/pkg/ipc/listener_windows_test.go new file mode 100644 index 00000000000..ac131fa2bd0 --- /dev/null +++ b/pkg/ipc/listener_windows_test.go @@ -0,0 +1,32 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License 2.0; +// you may not use this file except in compliance with the Elastic License 2.0. + +//go:build windows + +package ipc + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/elastic/elastic-agent-libs/logp" +) + +func TestCreateListener(t *testing.T) { + name := "npipe:///testpipe" + + // try creating and closing servers with same name multiple times + for range 1000 { + lis, err := CreateListener(logp.NewNopLogger(), name) + require.NoError(t, err) + require.NotNil(t, lis) + s := &http.Server{} //nolint:gosec // this is a test + go func() { + _ = s.Serve(lis) + }() + require.NoError(t, s.Close()) + } +}