mirror of
https://github.com/clearlinux/docker.git
synced 2026-10-04 07:48:44 +00:00
Merge pull request #6199 from icecrime/event_subscription_refactoring
Event subscription refactoring
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func NewJSONMessagePublisher() *JSONMessagePublisher {
|
||||
return &JSONMessagePublisher{}
|
||||
}
|
||||
|
||||
type JSONMessageListener chan<- JSONMessage
|
||||
|
||||
type JSONMessagePublisher struct {
|
||||
m sync.RWMutex
|
||||
subscribers []JSONMessageListener
|
||||
}
|
||||
|
||||
func (p *JSONMessagePublisher) Subscribe(l JSONMessageListener) {
|
||||
p.m.Lock()
|
||||
p.subscribers = append(p.subscribers, l)
|
||||
p.m.Unlock()
|
||||
}
|
||||
|
||||
func (p *JSONMessagePublisher) SubscribersCount() int {
|
||||
p.m.RLock()
|
||||
count := len(p.subscribers)
|
||||
p.m.RUnlock()
|
||||
return count
|
||||
}
|
||||
|
||||
// Unsubscribe closes and removes the specified listener from the list of
|
||||
// previously registed ones.
|
||||
// It returns a boolean value indicating if the listener was successfully
|
||||
// found, closed and unregistered.
|
||||
func (p *JSONMessagePublisher) Unsubscribe(l JSONMessageListener) bool {
|
||||
p.m.Lock()
|
||||
defer p.m.Unlock()
|
||||
|
||||
for i, subscriber := range p.subscribers {
|
||||
if subscriber == l {
|
||||
close(l)
|
||||
p.subscribers = append(p.subscribers[:i], p.subscribers[i+1:]...)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *JSONMessagePublisher) Publish(m JSONMessage) {
|
||||
p.m.RLock()
|
||||
for _, subscriber := range p.subscribers {
|
||||
// We give each subscriber a 100ms time window to receive the event,
|
||||
// after which we move to the next.
|
||||
select {
|
||||
case subscriber <- m:
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
}
|
||||
}
|
||||
p.m.RUnlock()
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func assertSubscribersCount(t *testing.T, q *JSONMessagePublisher, expected int) {
|
||||
if q.SubscribersCount() != expected {
|
||||
t.Fatalf("Expected %d registered subscribers, got %d", expected, q.SubscribersCount())
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONMessagePublisherSubscription(t *testing.T) {
|
||||
q := NewJSONMessagePublisher()
|
||||
l1 := make(chan JSONMessage)
|
||||
l2 := make(chan JSONMessage)
|
||||
|
||||
assertSubscribersCount(t, q, 0)
|
||||
q.Subscribe(l1)
|
||||
assertSubscribersCount(t, q, 1)
|
||||
q.Subscribe(l2)
|
||||
assertSubscribersCount(t, q, 2)
|
||||
|
||||
q.Unsubscribe(l1)
|
||||
q.Unsubscribe(l2)
|
||||
assertSubscribersCount(t, q, 0)
|
||||
}
|
||||
|
||||
func TestJSONMessagePublisherPublish(t *testing.T) {
|
||||
q := NewJSONMessagePublisher()
|
||||
l1 := make(chan JSONMessage)
|
||||
l2 := make(chan JSONMessage)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-l1:
|
||||
close(l1)
|
||||
l1 = nil
|
||||
case <-l2:
|
||||
close(l2)
|
||||
l2 = nil
|
||||
case <-time.After(1 * time.Second):
|
||||
q.Unsubscribe(l1)
|
||||
q.Unsubscribe(l2)
|
||||
t.Fatal("Timeout waiting for broadcasted message")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
q.Subscribe(l1)
|
||||
q.Subscribe(l2)
|
||||
q.Publish(JSONMessage{})
|
||||
}
|
||||
|
||||
func TestJSONMessagePublishTimeout(t *testing.T) {
|
||||
q := NewJSONMessagePublisher()
|
||||
l := make(chan JSONMessage)
|
||||
q.Subscribe(l)
|
||||
|
||||
c := make(chan struct{})
|
||||
go func() {
|
||||
q.Publish(JSONMessage{})
|
||||
close(c)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-c:
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("Timeout publishing message")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user