diff --git a/event/subscription.go b/event/subscription.go index 6c62874719..1c1626b165 100644 --- a/event/subscription.go +++ b/event/subscription.go @@ -153,14 +153,21 @@ func (s *resubscribeSub) Err() <-chan error { } func (s *resubscribeSub) loop() { - defer close(s.err) var done bool + var unsubbed bool + defer func() { + close(s.err) + // Read unsub chan to avoid blocking Unsubscribe + if !unsubbed { + <-s.unsub + } + }() for !done { sub := s.subscribe() if sub == nil { break } - done = s.waitForError(sub) + done, unsubbed = s.waitForError(sub) sub.Unsubscribe() } } @@ -197,14 +204,14 @@ func (s *resubscribeSub) subscribe() Subscription { } } -func (s *resubscribeSub) waitForError(sub Subscription) bool { +func (s *resubscribeSub) waitForError(sub Subscription) (bool, bool) { defer sub.Unsubscribe() select { case err := <-sub.Err(): s.lastSubErr = err - return err == nil + return err == nil, false case <-s.unsub: - return true + return true, true } } diff --git a/event/subscription_test.go b/event/subscription_test.go index ba081705c4..06b4a4941b 100644 --- a/event/subscription_test.go +++ b/event/subscription_test.go @@ -154,3 +154,23 @@ func TestResubscribeWithErrorHandler(t *testing.T) { t.Fatalf("unexpected subscription errors %v, want %v", subErrs, expectedSubErrs) } } + +func TestResubscribeWithCompletedSubscription(t *testing.T) { + t.Parallel() + + innerSubDone := make(chan struct{}, 1) + sub := ResubscribeErr(100*time.Millisecond, func(ctx context.Context, lastErr error) (Subscription, error) { + return NewSubscription(func(unsubscribed <-chan struct{}) error { + select { + case <-time.After(2 * time.Second): + innerSubDone <- struct{}{} + return nil + case <-unsubscribed: + return nil + } + }), nil + }) + + <-innerSubDone + sub.Unsubscribe() +}