From 85876310af24dc7542d188c479b894e22cb0f024 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Tue, 23 Jul 2019 14:24:21 +0200 Subject: [PATCH] readdb: fix deadlock in Run method In runservice readdb Run method we could end with a deadlock if two of the goroutines that call HandleEvents.* try to write to the errCh at the same time before the errCh is read. If this happens one of the two will be blocked on writing to the channel but the read won't happen since it'll blocked by wg.Wait(). Fix this doing: * use a buffered channel large as the number of executed goroutines. * create a new errCh at every loop (so we'll ignore later errors after the first one) Note: we could also use a non blocking send to avoid this situation but we should also start the wg.Wait before the goroutines or earlier errors could be lost causing another kind of hang. --- internal/services/configstore/readdb/readdb.go | 2 +- internal/services/runservice/readdb/readdb.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/services/configstore/readdb/readdb.go b/internal/services/configstore/readdb/readdb.go index 005c3a7..ad29925 100644 --- a/internal/services/configstore/readdb/readdb.go +++ b/internal/services/configstore/readdb/readdb.go @@ -424,7 +424,6 @@ func (r *ReadDB) Run(ctx context.Context) error { } r.SetInitialized(true) - errCh := make(chan error) for { for { initialized := r.IsInitialized() @@ -441,6 +440,7 @@ func (r *ReadDB) Run(ctx context.Context) error { time.Sleep(1 * time.Second) } + errCh := make(chan error, 1) ctx, cancel := context.WithCancel(ctx) wg := &sync.WaitGroup{} diff --git a/internal/services/runservice/readdb/readdb.go b/internal/services/runservice/readdb/readdb.go index 1974cd6..405410c 100644 --- a/internal/services/runservice/readdb/readdb.go +++ b/internal/services/runservice/readdb/readdb.go @@ -274,7 +274,6 @@ func (r *ReadDB) Run(ctx context.Context) error { } r.SetInitialized(true) - errCh := make(chan error) for { for { initialized := r.IsInitialized() @@ -291,6 +290,7 @@ func (r *ReadDB) Run(ctx context.Context) error { time.Sleep(1 * time.Second) } + errCh := make(chan error, 2) ctx, cancel := context.WithCancel(ctx) wg := &sync.WaitGroup{}