From f217a2f54d0428c4abf2701863e26cd00f6c8b2b Mon Sep 17 00:00:00 2001 From: dawn Date: Fri, 17 Jul 2026 09:28:39 +0000 Subject: [PATCH] spindle/engines/nixery: make engine fully lazy Signed-off-by: dawn --- spindle/engines/nixery/engine.go | 33 ++++++++++++++++++++++++--------- spindle/engines/nixery/engine_test.go | 25 +++++++++++++++++++++++++ 2 file(s) changed, 49 insertion(s)(+), 9 deletion(s)(-) diff --git a/spindle/engines/nixery/engine.go b/spindle/engines/nixery/engine.go --- a/spindle/engines/nixery/engine.go +++ b/spindle/engines/nixery/engine.go @@ -35,9 +35,10 @@ type cleanupFunc func(context.Context) error type Engine struct { - docker client.APIClient - l *slog.Logger - cfg *config.Config + dockerMu sync.Mutex + docker client.APIClient + l *slog.Logger + cfg *config.Config slotter engine.WorkflowSlotter @@ -164,15 +165,9 @@ return path.Join(nixery, dependencies) } func New(ctx context.Context, cfg *config.Config) (*Engine, error) { - dcli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) - if err != nil { - return nil, err - } - l := log.FromContext(ctx).With("component", "spindle") e := &Engine{ - docker: dcli, l: l, cfg: cfg, slotter: engine.NewSemaphoreSlotter(cfg.NixeryPipelines.MaxConcurrentWorkflows), @@ -181,6 +176,22 @@ e.cleanup = make(map[string][]cleanupFunc) return e, nil +} + +func (e *Engine) ensureDocker() (client.APIClient, error) { + e.dockerMu.Lock() + defer e.dockerMu.Unlock() + + if e.docker != nil { + return e.docker, nil + } + + dcli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return nil, err + } + e.docker = dcli + return dcli, nil } func (e *Engine) AcquireWorkflowSlot( @@ -214,6 +225,10 @@ if err != nil { err = fmt.Errorf("Failed to setup container:\n%w", err) } }() + + if _, err := e.ensureDocker(); err != nil { + return err + } /// -------------------------NETWORK CREATION--------------------------------------- _, err = e.docker.NetworkCreate(ctx, networkName(wid), network.CreateOptions{ diff --git a/spindle/engines/nixery/engine_test.go b/spindle/engines/nixery/engine_test.go new file mode 100644 --- /dev/null +++ b/spindle/engines/nixery/engine_test.go @@ -0,0 +1,25 @@ +package nixery + +import ( + "context" + "testing" + + "tangled.org/core/spindle/config" +) + +func TestNewDefersDockerClientUntilWorkflowSetup(t *testing.T) { + t.Setenv("DOCKER_HOST", "tcp://127.0.0.1:2376") + t.Setenv("DOCKER_TLS_VERIFY", "1") + t.Setenv("DOCKER_CERT_PATH", t.TempDir()) + + e, err := New(context.Background(), &config.Config{}) + if err != nil { + t.Fatal(err) + } + if e.docker != nil { + t.Fatal("docker client initialized during engine initialization") + } + if _, err := e.ensureDocker(); err == nil { + t.Fatal("expected incomplete Docker TLS configuration to fail when first used") + } +} -- tangled.sh