From 55df2b502cfcab800f1730ae89cec756b75757af Mon Sep 17 00:00:00 2001 From: andig Date: Tue, 26 Dec 2023 23:08:28 +0100 Subject: [PATCH] Fix deadlock (#11244) This PR uses a go routine when sending would otherwise block. --- core/loadpoint.go | 16 ++++++++++++++-- core/loadpoint_test.go | 1 + core/site.go | 12 +++++++++--- util/tee.go | 2 +- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/core/loadpoint.go b/core/loadpoint.go index d4c2e415f..fbe24e6da 100644 --- a/core/loadpoint.go +++ b/core/loadpoint.go @@ -384,8 +384,20 @@ func (lp *Loadpoint) pushEvent(event string) { // publish sends values to UI and databases func (lp *Loadpoint) publish(key string, val interface{}) { - if lp.uiChan != nil { - lp.uiChan <- util.Param{Key: key, Val: val} + // test helper + if lp.uiChan == nil { + return + } + + p := util.Param{Key: key, Val: val} + + // https://github.com/evcc-io/evcc/issues/11191 prevent deadlock + select { + case lp.uiChan <- p: + default: + go func() { + lp.uiChan <- p + }() } } diff --git a/core/loadpoint_test.go b/core/loadpoint_test.go index 9411da117..89330116a 100644 --- a/core/loadpoint_test.go +++ b/core/loadpoint_test.go @@ -526,6 +526,7 @@ func cacheExpecter(t *testing.T, lp *Loadpoint) (*util.Cache, func(key string, v go cache.Run(paramC) expect := func(key string, val interface{}) { + time.Sleep(100 * time.Millisecond) // wait for cache to catch up p := cache.Get(key) t.Logf("%s: %.f", key, p.Val) // REMOVE if p.Val != val { diff --git a/core/site.go b/core/site.go index 3d97340a8..1213948ec 100644 --- a/core/site.go +++ b/core/site.go @@ -360,9 +360,15 @@ func (site *Site) publish(key string, val interface{}) { val = s.String() } - site.uiChan <- util.Param{ - Key: key, - Val: val, + p := util.Param{Key: key, Val: val} + + // https://github.com/evcc-io/evcc/issues/11191 prevent deadlock + select { + case site.uiChan <- p: + default: + go func() { + site.uiChan <- p + }() } } diff --git a/util/tee.go b/util/tee.go index 7bbae57db..6fb4e8736 100644 --- a/util/tee.go +++ b/util/tee.go @@ -20,7 +20,7 @@ type Tee struct { func (t *Tee) Attach() <-chan Param { // TODO find better approach to prevent deadlocks // this will buffer the receiver channel to prevent deadlocks when consumers use mutex-protected loadpoint api - out := make(chan Param, 16) + out := make(chan Param, 128) t.add(out) return out }