events: don't explode when destroying a bus

Only attempt to close channels once, rather than per topic
they are subscribed to.
This commit is contained in:
Matthew Penner
2022-01-20 09:48:18 -07:00
parent 6d8c1d2225
commit 4ba5fe2866
4 changed files with 39 additions and 22 deletions

View File

@@ -3,6 +3,8 @@ package events
import (
"strings"
"sync"
"github.com/apex/log"
)
type Listener chan Event
@@ -31,8 +33,15 @@ func (b *Bus) Off(listener Listener, topics ...string) {
b.listenersMx.Lock()
defer b.listenersMx.Unlock()
var closed bool
for _, topic := range topics {
b.off(topic, listener)
ok := b.off(topic, listener)
if !closed && ok {
log.Debug("closing event channel!")
close(listener)
closed = true
}
}
}
@@ -116,11 +125,30 @@ func (b *Bus) Destroy() {
b.listenersMx.Lock()
defer b.listenersMx.Unlock()
// Track what listeners have already been closed. Because the same listener
// can be listening on multiple topics, we need a way to essentially
// "de-duplicate" all the listeners across all the topics.
var closed []Listener
for _, listeners := range b.listeners {
for _, listener := range listeners {
if contains(closed, listener) {
continue
}
close(listener)
closed = append(closed, listener)
}
}
b.listeners = make(map[string][]Listener)
}
func contains(closed []Listener, listener Listener) bool {
for _, c := range closed {
if c == listener {
return true
}
}
return false
}

View File

@@ -36,8 +36,6 @@ func TestBus_Off(t *testing.T) {
bus.Off(listener, topic)
g.Assert(len(bus.listeners[topic])).Equal(0, "Topic still has one or more listeners")
close(listener)
})
g.It("unregisters correct listener", func() {
@@ -62,9 +60,6 @@ func TestBus_Off(t *testing.T) {
// Cleanup
bus.Off(listener2, topic)
close(listener)
close(listener2)
close(listener3)
})
})
}
@@ -91,7 +86,6 @@ func TestBus_On(t *testing.T) {
// Cleanup
bus.Off(listener, topic)
close(listener)
})
})
}
@@ -127,7 +121,6 @@ func TestBus_Publish(t *testing.T) {
<-done
// Cleanup
close(listener)
bus.Off(listener, topic)
})
@@ -172,9 +165,6 @@ func TestBus_Publish(t *testing.T) {
bus.Off(listener, topic)
bus.Off(listener2, topic)
bus.Off(listener3, topic)
close(listener)
close(listener2)
close(listener3)
})
})
}