surface honeybee.EventDialFailed through the prism event pipeline

This commit is contained in:
Jay
2026-06-04 17:46:47 -04:00
parent df0a968907
commit 69f9219819
7 changed files with 86 additions and 21 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ type AuthManager struct {
challenge string challenge string
inbox <-chan InboxMessage inbox <-chan InboxMessage
events <-chan OutboundPoolEvent events <-chan PoolEvent
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
+16 -12
View File
@@ -29,6 +29,7 @@ type EmbassyEventKind int
const ( const (
EventConnected EmbassyEventKind = iota EventConnected EmbassyEventKind = iota
EventDisconnected EventDisconnected
EventDialFailed
EventEmbassyUnknown EventEmbassyUnknown
) )
@@ -38,15 +39,18 @@ func mapEmbassyEvent(kind honeybee.PoolEventKind) EmbassyEventKind {
return EventConnected return EventConnected
case honeybee.EventDisconnected: case honeybee.EventDisconnected:
return EventDisconnected return EventDisconnected
case honeybee.EventDialFailed:
return EventDialFailed
default: default:
return EventEmbassyUnknown return EventEmbassyUnknown
} }
} }
type OutboundPoolEvent struct { type PoolEvent struct {
ID string ID string
Kind EmbassyEventKind Kind EmbassyEventKind
At time.Time At time.Time
Err error
} }
type InboxMessage struct { type InboxMessage struct {
@@ -85,7 +89,7 @@ func WithEmbassyObserver(o observer.Observer) EmbassyOption {
type Embassy struct { type Embassy struct {
pool EmbassyPlugin pool EmbassyPlugin
envoys map[string]*Envoy envoys map[string]*Envoy
eventSubs map[string]chan<- OutboundPoolEvent eventSubs map[string]chan<- PoolEvent
inboxSubs map[string]chan<- InboxMessage inboxSubs map[string]chan<- InboxMessage
ctx context.Context ctx context.Context
@@ -111,7 +115,7 @@ func NewEmbassy(
e := &Embassy{ e := &Embassy{
pool: pool, pool: pool,
envoys: make(map[string]*Envoy), envoys: make(map[string]*Envoy),
eventSubs: make(map[string]chan<- OutboundPoolEvent), eventSubs: make(map[string]chan<- PoolEvent),
inboxSubs: make(map[string]chan<- InboxMessage), inboxSubs: make(map[string]chan<- InboxMessage),
ctx: ctx, ctx: ctx,
cancel: cancel, cancel: cancel,
@@ -205,8 +209,8 @@ func (e *Embassy) send(url string, data []byte) error {
return e.pool.Send(url, data) return e.pool.Send(url, data)
} }
func (e *Embassy) subscribeEventsLock(url string) <-chan OutboundPoolEvent { func (e *Embassy) subscribeEventsLock(url string) <-chan PoolEvent {
ch := make(chan OutboundPoolEvent) ch := make(chan PoolEvent)
e.eventSubs[url] = ch e.eventSubs[url] = ch
return ch return ch
} }
@@ -261,8 +265,8 @@ func (e *Embassy) routeEvents() {
select { select {
case <-e.ctx.Done(): case <-e.ctx.Done():
return return
case sub <- OutboundPoolEvent{ case sub <- PoolEvent{
ID: ev.ID, Kind: mapEmbassyEvent(ev.Kind), At: ev.At, ID: ev.ID, Kind: mapEmbassyEvent(ev.Kind), At: ev.At, Err: ev.Err,
}: }:
} }
} }
@@ -312,9 +316,9 @@ type Envoy struct {
terminate func() terminate func()
queue chan []byte queue chan []byte
send func(data []byte) error send func(data []byte) error
events <-chan OutboundPoolEvent events <-chan PoolEvent
inbox <-chan InboxMessage inbox <-chan InboxMessage
eventSubs []chan<- OutboundPoolEvent eventSubs []chan<- PoolEvent
labelledInboxSubs map[string][]chan<- InboxMessage labelledInboxSubs map[string][]chan<- InboxMessage
inboxSubs []chan<- InboxMessage inboxSubs []chan<- InboxMessage
@@ -332,7 +336,7 @@ func newEnvoy(
url string, url string,
terminate func(), terminate func(),
send func(data []byte) error, send func(data []byte) error,
events <-chan OutboundPoolEvent, events <-chan PoolEvent,
inbox <-chan InboxMessage, inbox <-chan InboxMessage,
observer observer.Observer, observer observer.Observer,
handler slog.Handler, handler slog.Handler,
@@ -411,10 +415,10 @@ func (e *Envoy) Send(data []byte) error {
return e.send(data) return e.send(data)
} }
func (e *Envoy) SubscribeEvents() <-chan OutboundPoolEvent { func (e *Envoy) SubscribeEvents() <-chan PoolEvent {
e.mu.Lock() e.mu.Lock()
defer e.mu.Unlock() defer e.mu.Unlock()
ch := make(chan OutboundPoolEvent) ch := make(chan PoolEvent)
e.eventSubs = append(e.eventSubs, ch) e.eventSubs = append(e.eventSubs, ch)
return ch return ch
} }
+56
View File
@@ -1,6 +1,7 @@
package prism package prism
import ( import (
"errors"
"git.wisehodl.dev/jay/go-honeybee" "git.wisehodl.dev/jay/go-honeybee"
"git.wisehodl.dev/jay/go-roots-ws" "git.wisehodl.dev/jay/go-roots-ws"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@@ -91,3 +92,58 @@ func TestEmbassy_Dispatch(t *testing.T) {
envoy = embassy.Call(p.url) envoy = embassy.Call(p.url)
assert.Nil(t, envoy) assert.Nil(t, envoy)
} }
func TestEmbassy_DialFailed_Routing(t *testing.T) {
t.Run("routed to correct subscriber with Err set", func(t *testing.T) {
p, envoy := newMockEnvoy(t)
sub := envoy.SubscribeEvents()
dialErr := errors.New("connection refused")
p.dialFail(dialErr)
var got PoolEvent
Eventually(t, func() bool {
select {
case ev := <-sub:
got = ev
return true
default:
return false
}
}, "expected EventDialFailed to be routed to subscriber")
assert.Equal(t, EventDialFailed, got.Kind)
assert.ErrorIs(t, got.Err, dialErr)
assert.Equal(t, p.url, got.ID)
})
t.Run("not routed to unrelated envoy subscriber", func(t *testing.T) {
p := newMockPool(t)
url1 := "wss://peer1"
url2 := "wss://peer2"
added := make(chan struct{}, 2)
p.plugin.Connect = func(url string, opts ...honeybee.ConnectOption) error {
added <- struct{}{}
return nil
}
emb := NewEmbassy(p.ctx, p.plugin)
emb.Dispatch(url1)
emb.Dispatch(url2)
envoy2 := emb.Call(url2)
sub2 := envoy2.SubscribeEvents()
p.dialFail(errors.New("refused"))
Never(t, func() bool {
select {
case <-sub2:
return true
default:
return false
}
}, "EventDialFailed for a different peer must not reach unrelated subscriber")
})
}
+6 -6
View File
@@ -60,12 +60,12 @@ func TestEnvoy_IsConnected(t *testing.T) {
ctx := component.MustNew(context.Background(), "prism", "test") ctx := component.MustNew(context.Background(), "prism", "test")
mu := sync.RWMutex{} mu := sync.RWMutex{}
url := "wss://test" url := "wss://test"
events := make(chan OutboundPoolEvent) events := make(chan PoolEvent)
envoy := newEnvoy(ctx, url, nil, nil, events, nil, nil, nil) envoy := newEnvoy(ctx, url, nil, nil, events, nil, nil, nil)
eventSub := envoy.SubscribeEvents() eventSub := envoy.SubscribeEvents()
gotEvents := []OutboundPoolEvent{} gotEvents := []PoolEvent{}
go func() { go func() {
for ev := range eventSub { for ev := range eventSub {
mu.Lock() mu.Lock()
@@ -74,7 +74,7 @@ func TestEnvoy_IsConnected(t *testing.T) {
} }
}() }()
events <- OutboundPoolEvent{ events <- PoolEvent{
ID: url, Kind: EventConnected, At: time.Now()} ID: url, Kind: EventConnected, At: time.Now()}
Eventually(t, func() bool { Eventually(t, func() bool {
@@ -86,12 +86,12 @@ func TestEnvoy_Events(t *testing.T) {
ctx := component.MustNew(context.Background(), "prism", "test") ctx := component.MustNew(context.Background(), "prism", "test")
mu := sync.RWMutex{} mu := sync.RWMutex{}
url := "wss://test" url := "wss://test"
events := make(chan OutboundPoolEvent) events := make(chan PoolEvent)
envoy := newEnvoy(ctx, url, nil, nil, events, nil, nil, nil) envoy := newEnvoy(ctx, url, nil, nil, events, nil, nil, nil)
eventSub := envoy.SubscribeEvents() eventSub := envoy.SubscribeEvents()
gotEvents := []OutboundPoolEvent{} gotEvents := []PoolEvent{}
go func() { go func() {
for ev := range eventSub { for ev := range eventSub {
mu.Lock() mu.Lock()
@@ -100,7 +100,7 @@ func TestEnvoy_Events(t *testing.T) {
} }
}() }()
events <- OutboundPoolEvent{ events <- PoolEvent{
ID: url, Kind: EventConnected, At: time.Now()} ID: url, Kind: EventConnected, At: time.Now()}
Eventually(t, func() bool { Eventually(t, func() bool {
+5
View File
@@ -95,6 +95,11 @@ func (p *mockPool) disconnect() {
ID: p.url, Kind: honeybee.EventDisconnected, At: time.Now()} ID: p.url, Kind: honeybee.EventDisconnected, At: time.Now()}
} }
func (p *mockPool) dialFail(err error) {
p.events <- honeybee.PoolEvent{
ID: p.url, Kind: honeybee.EventDialFailed, Err: err, At: time.Now()}
}
func (p *mockPool) receive(data []byte) { func (p *mockPool) receive(data []byte) {
p.inbox <- honeybee.InboxMessage{ p.inbox <- honeybee.InboxMessage{
ID: p.url, ID: p.url,
+1 -1
View File
@@ -69,7 +69,7 @@ type EventPublisher struct {
pending map[string]*pendingEntry // event id -> pending entry pending map[string]*pendingEntry // event id -> pending entry
inbox <-chan InboxMessage inbox <-chan InboxMessage
events <-chan OutboundPoolEvent events <-chan PoolEvent
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
+1 -1
View File
@@ -115,7 +115,7 @@ type RequestManager struct {
reqs map[string]*request reqs map[string]*request
envoy *Envoy envoy *Envoy
events <-chan OutboundPoolEvent events <-chan PoolEvent
inbox <-chan InboxMessage inbox <-chan InboxMessage
ctx context.Context ctx context.Context