From 4a7cb7d6d87b97709c9831b049bf4ac0c78e2311 Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 10 Jun 2026 22:35:54 +0200 Subject: [PATCH] chore: release device context on failed creation (#30714) --- cmd/setup.go | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/cmd/setup.go b/cmd/setup.go index 79e2216d0..17205ac62 100644 --- a/cmd/setup.go +++ b/cmd/setup.go @@ -296,23 +296,25 @@ func validateConfigurableCircuits(children []config.Config) error { type newFromConfFunc[T any] func(context.Context, string, map[string]any) (T, error) func staticInstance[T any](typ string, cc config.Named, newFromConf newFromConfFunc[T], h config.Handler[T]) error { - ctx, cancel := context.WithCancel(util.WithLogger(context.TODO(), util.NewLogger(cc.Name))) //nolint:govet + ctx, cancel := context.WithCancel(util.WithLogger(context.TODO(), util.NewLogger(cc.Name))) instance, err := newFromConf(ctx, cc.Type, cc.Other) if err != nil { err = &DeviceError{cc.Name, fmt.Errorf("cannot create %s '%s': %w", typ, cc.Name, err)} } + // ctx lives for the device lifetime- only release it on failure + defer func() { + if err != nil { + cancel() + } + }() + if e := h.Add(config.NewStaticDevice(cc, instance)); e != nil && err == nil { err = &DeviceError{cc.Name, e} } - // release resources - if err != nil { - cancel() - } - - return err //nolint:govet + return err } // loggerForConfig creates a logger with sensible name for (custom) configurable device @@ -326,13 +328,20 @@ func loggerForConfig(conf *config.Config) *util.Logger { func configurableInstance[T any](typ string, conf *config.Config, newFromConf newFromConfFunc[T], h config.Handler[T]) error { cc := conf.Named() - ctx, cancel := context.WithCancel(util.WithLogger(context.TODO(), loggerForConfig(conf))) //nolint:govet + ctx, cancel := context.WithCancel(util.WithLogger(context.TODO(), loggerForConfig(conf))) typ, other, err := config.CustomDevice(cc.Type, cc.Other) if err != nil { err = &DeviceError{cc.Name, fmt.Errorf("cannot decode custom %s '%s': %w", typ, cc.Name, err)} } + // ctx lives for the device lifetime- only release it on failure + defer func() { + if err != nil { + cancel() + } + }() + var instance T if err == nil { instance, err = newFromConf(ctx, typ, other) @@ -345,12 +354,7 @@ func configurableInstance[T any](typ string, conf *config.Config, newFromConf ne err = &DeviceError{cc.Name, e} } - // release resources - if err != nil { - cancel() - } - - return err //nolint:govet + return err } func configureMeters(static []config.Named, names ...string) error {