session: unified inbox channel with EOF sentinel; session owns event forwarding
This commit is contained in:
+13
-4
@@ -6,6 +6,7 @@ import (
|
|||||||
"git.wisehodl.dev/jay/go-mana-component"
|
"git.wisehodl.dev/jay/go-mana-component"
|
||||||
"git.wisehodl.dev/jay/go-roots-ws"
|
"git.wisehodl.dev/jay/go-roots-ws"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@@ -98,11 +99,14 @@ type mockSessionHarness struct {
|
|||||||
id string
|
id string
|
||||||
filters [][]byte
|
filters [][]byte
|
||||||
req []byte
|
req []byte
|
||||||
eose chan struct{}
|
inbox chan sessionMessage
|
||||||
closed chan struct{}
|
events chan ReqEvent
|
||||||
|
closed chan ReqClosed
|
||||||
|
closedOnce *sync.Once
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
sent chan []byte
|
sent chan []byte
|
||||||
send func([]byte) error
|
send func([]byte) error
|
||||||
|
preterminate func()
|
||||||
terminatedWith chan terminateReason
|
terminatedWith chan terminateReason
|
||||||
terminate func(terminateReason)
|
terminate func(terminateReason)
|
||||||
}
|
}
|
||||||
@@ -116,6 +120,8 @@ func newMockSessionHarness() *mockSessionHarness {
|
|||||||
sent <- data
|
sent <- data
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
inbox := make(chan sessionMessage, 16)
|
||||||
|
preterminate := func() { close(inbox) }
|
||||||
terminatedWith := make(chan terminateReason, 1)
|
terminatedWith := make(chan terminateReason, 1)
|
||||||
terminate := func(r terminateReason) { terminatedWith <- r }
|
terminate := func(r terminateReason) { terminatedWith <- r }
|
||||||
|
|
||||||
@@ -124,11 +130,14 @@ func newMockSessionHarness() *mockSessionHarness {
|
|||||||
id: id,
|
id: id,
|
||||||
filters: filters,
|
filters: filters,
|
||||||
req: envelope.EncloseReq(id, filters),
|
req: envelope.EncloseReq(id, filters),
|
||||||
eose: make(chan struct{}),
|
inbox: inbox,
|
||||||
closed: make(chan struct{}),
|
events: make(chan ReqEvent, 16),
|
||||||
|
closed: make(chan ReqClosed, 16),
|
||||||
|
closedOnce: &sync.Once{},
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
sent: sent,
|
sent: sent,
|
||||||
send: send,
|
send: send,
|
||||||
|
preterminate: preterminate,
|
||||||
terminatedWith: terminatedWith,
|
terminatedWith: terminatedWith,
|
||||||
terminate: terminate,
|
terminate: terminate,
|
||||||
}
|
}
|
||||||
|
|||||||
+122
-75
@@ -31,7 +31,7 @@ type ReqClosed struct {
|
|||||||
type RequestManager struct {
|
type RequestManager struct {
|
||||||
reqs map[string]*request
|
reqs map[string]*request
|
||||||
sessions map[string]*session
|
sessions map[string]*session
|
||||||
inboxSubs map[string]*sessionSub
|
inboxSubs map[string]chan<- sessionMessage
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
sessionWg sync.WaitGroup
|
sessionWg sync.WaitGroup
|
||||||
|
|
||||||
@@ -61,24 +61,27 @@ type session struct {
|
|||||||
id string
|
id string
|
||||||
req []byte
|
req []byte
|
||||||
|
|
||||||
eose <-chan struct{}
|
inbox <-chan sessionMessage
|
||||||
closed <-chan struct{}
|
forwardEvent chan<- ReqEvent
|
||||||
|
forwardClosed chan<- ReqClosed
|
||||||
|
closedOnce *sync.Once
|
||||||
|
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
send func([]byte) error
|
send func([]byte) error
|
||||||
terminate func(terminateReason)
|
preterminate func()
|
||||||
closeOnEOSE bool
|
terminate func(terminateReason)
|
||||||
|
closeOnEOSE bool
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type sessionSub struct {
|
type sessionMessage struct {
|
||||||
eose chan<- struct{}
|
label string
|
||||||
closed chan<- struct{}
|
peerID string
|
||||||
eoseOnce sync.Once
|
receivedAt time.Time
|
||||||
closedOnce sync.Once
|
data []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
type terminateReason int
|
type terminateReason int
|
||||||
@@ -117,7 +120,7 @@ func NewRequestManager(e *Envoy) *RequestManager {
|
|||||||
m := &RequestManager{
|
m := &RequestManager{
|
||||||
reqs: make(map[string]*request),
|
reqs: make(map[string]*request),
|
||||||
sessions: make(map[string]*session),
|
sessions: make(map[string]*session),
|
||||||
inboxSubs: make(map[string]*sessionSub),
|
inboxSubs: make(map[string]chan<- sessionMessage),
|
||||||
|
|
||||||
envoy: e,
|
envoy: e,
|
||||||
events: e.SubscribeEvents(),
|
events: e.SubscribeEvents(),
|
||||||
@@ -179,24 +182,18 @@ func (m *RequestManager) Query(
|
|||||||
}
|
}
|
||||||
|
|
||||||
id := generateID()
|
id := generateID()
|
||||||
buffer := make(chan ReqEvent, 64)
|
|
||||||
eventsCh := make(chan ReqEvent)
|
eventsCh := make(chan ReqEvent)
|
||||||
closedCh := make(chan ReqClosed, 1)
|
closedCh := make(chan ReqClosed, 1)
|
||||||
|
|
||||||
req := &request{
|
req := &request{
|
||||||
id: id,
|
id: id,
|
||||||
filters: filters,
|
filters: filters,
|
||||||
buffer: buffer,
|
buffer: eventsCh,
|
||||||
events: eventsCh,
|
|
||||||
closed: closedCh,
|
closed: closedCh,
|
||||||
}
|
}
|
||||||
|
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
m.reqs[id] = req
|
m.reqs[id] = req
|
||||||
go func() {
|
|
||||||
bufferedPipe(buffer, eventsCh)
|
|
||||||
close(eventsCh)
|
|
||||||
}()
|
|
||||||
|
|
||||||
m.spawnSession(req, true)
|
m.spawnSession(req, true)
|
||||||
m.mu.Unlock()
|
m.mu.Unlock()
|
||||||
@@ -274,19 +271,20 @@ func (m *RequestManager) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *RequestManager) spawnSession(req *request, query bool) {
|
func (m *RequestManager) spawnSession(req *request, query bool) {
|
||||||
eose := make(chan struct{})
|
sessionInbox := make(chan sessionMessage, 64)
|
||||||
closed := make(chan struct{})
|
m.inboxSubs[req.id] = sessionInbox
|
||||||
|
|
||||||
sub := &sessionSub{eose: eose, closed: closed}
|
|
||||||
m.inboxSubs[req.id] = sub
|
|
||||||
|
|
||||||
var once sync.Once
|
var once sync.Once
|
||||||
|
preterminate := func() {
|
||||||
|
m.mu.Lock()
|
||||||
|
delete(m.inboxSubs, req.id)
|
||||||
|
m.mu.Unlock()
|
||||||
|
sessionInbox <- sessionMessage{label: "EOF"}
|
||||||
|
}
|
||||||
|
|
||||||
terminate := func(r terminateReason) {
|
terminate := func(r terminateReason) {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
close(eose)
|
|
||||||
close(closed)
|
|
||||||
delete(m.inboxSubs, req.id)
|
|
||||||
delete(m.sessions, req.id)
|
delete(m.sessions, req.id)
|
||||||
m.mu.Unlock()
|
m.mu.Unlock()
|
||||||
m.sessionWg.Done()
|
m.sessionWg.Done()
|
||||||
@@ -304,10 +302,8 @@ func (m *RequestManager) spawnSession(req *request, query bool) {
|
|||||||
|
|
||||||
req_env := envelope.EncloseReq(req.id, req.filters)
|
req_env := envelope.EncloseReq(req.id, req.filters)
|
||||||
sess := newSession(
|
sess := newSession(
|
||||||
m.ctx, req.id, req_env,
|
m.ctx, req.id, req_env, sessionInbox, req.buffer, req.closed, &req.closedOnce,
|
||||||
eose, closed, m.done,
|
m.done, m.envoy.Send, preterminate, terminate, query, m.handler,
|
||||||
m.envoy.Send, terminate,
|
|
||||||
query, m.handler,
|
|
||||||
)
|
)
|
||||||
m.sessions[req.id] = sess
|
m.sessions[req.id] = sess
|
||||||
m.sessionWg.Add(1)
|
m.sessionWg.Add(1)
|
||||||
@@ -357,14 +353,16 @@ func (m *RequestManager) dispatchInbox(msg InboxMessage) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.mu.RLock()
|
m.mu.RLock()
|
||||||
req, ok := m.reqs[subID]
|
sub, ok := m.inboxSubs[subID]
|
||||||
m.mu.RUnlock()
|
m.mu.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
select {
|
sub <- sessionMessage{
|
||||||
case req.buffer <- ReqEvent{
|
label: "EVENT",
|
||||||
PeerID: msg.ID, ReceivedAt: msg.ReceivedAt, Data: event}:
|
peerID: msg.ID,
|
||||||
|
receivedAt: msg.ReceivedAt,
|
||||||
|
data: event,
|
||||||
}
|
}
|
||||||
case "EOSE":
|
case "EOSE":
|
||||||
subID, err := envelope.FindEOSE(msg.Data)
|
subID, err := envelope.FindEOSE(msg.Data)
|
||||||
@@ -377,31 +375,27 @@ func (m *RequestManager) dispatchInbox(msg InboxMessage) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sub.eoseOnce.Do(func() {
|
sub <- sessionMessage{
|
||||||
select {
|
label: "EOSE",
|
||||||
case sub.eose <- struct{}{}:
|
peerID: msg.ID,
|
||||||
default:
|
receivedAt: msg.ReceivedAt,
|
||||||
}
|
}
|
||||||
})
|
|
||||||
case "CLOSED":
|
case "CLOSED":
|
||||||
subID, message, err := envelope.FindClosed(msg.Data)
|
subID, message, err := envelope.FindClosed(msg.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
m.mu.RLock()
|
m.mu.RLock()
|
||||||
req, reqOk := m.reqs[subID]
|
sub, ok := m.inboxSubs[subID]
|
||||||
sub, subOk := m.inboxSubs[subID]
|
|
||||||
m.mu.RUnlock()
|
m.mu.RUnlock()
|
||||||
if reqOk {
|
if !ok {
|
||||||
req.closedOnce.Do(func() {
|
return
|
||||||
req.closed <- ReqClosed{
|
|
||||||
PeerID: msg.ID, ReceivedAt: msg.ReceivedAt, Data: message}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
if subOk {
|
sub <- sessionMessage{
|
||||||
sub.closedOnce.Do(func() {
|
label: "CLOSED",
|
||||||
sub.closed <- struct{}{}
|
peerID: msg.ID,
|
||||||
})
|
receivedAt: msg.ReceivedAt,
|
||||||
|
data: []byte(message),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -414,26 +408,32 @@ func newSession(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
id string,
|
id string,
|
||||||
req []byte,
|
req []byte,
|
||||||
eose <-chan struct{},
|
inbox <-chan sessionMessage,
|
||||||
closed <-chan struct{},
|
forwardEvent chan<- ReqEvent,
|
||||||
|
forwardClosed chan<- ReqClosed,
|
||||||
|
closedOnce *sync.Once,
|
||||||
done chan struct{},
|
done chan struct{},
|
||||||
send func(data []byte) error,
|
send func(data []byte) error,
|
||||||
|
preterminate func(),
|
||||||
terminate func(terminateReason),
|
terminate func(terminateReason),
|
||||||
isQuery bool,
|
isQuery bool,
|
||||||
handler slog.Handler,
|
handler slog.Handler,
|
||||||
) *session {
|
) *session {
|
||||||
ctx, cancel := context.WithCancel(component.MustExtend(ctx, "session"))
|
ctx, cancel := context.WithCancel(component.MustExtend(ctx, "session"))
|
||||||
s := &session{
|
s := &session{
|
||||||
id: id,
|
id: id,
|
||||||
req: req,
|
req: req,
|
||||||
eose: eose,
|
inbox: inbox,
|
||||||
closed: closed,
|
forwardEvent: forwardEvent,
|
||||||
done: done,
|
forwardClosed: forwardClosed,
|
||||||
send: send,
|
closedOnce: closedOnce,
|
||||||
terminate: terminate,
|
done: done,
|
||||||
closeOnEOSE: isQuery,
|
send: send,
|
||||||
ctx: ctx,
|
preterminate: preterminate,
|
||||||
cancel: cancel,
|
terminate: terminate,
|
||||||
|
closeOnEOSE: isQuery,
|
||||||
|
ctx: ctx,
|
||||||
|
cancel: cancel,
|
||||||
}
|
}
|
||||||
// create logger if handler is supplied
|
// create logger if handler is supplied
|
||||||
return s
|
return s
|
||||||
@@ -444,29 +444,76 @@ func (s *session) run() {
|
|||||||
sent := make(chan error, 1)
|
sent := make(chan error, 1)
|
||||||
go func() { sent <- s.send(s.req) }()
|
go func() { sent <- s.send(s.req) }()
|
||||||
|
|
||||||
|
drain := func() {
|
||||||
|
for msg := range s.inbox {
|
||||||
|
if msg.label == "EOF" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msg.label {
|
||||||
|
case "EVENT":
|
||||||
|
s.forwardEvent <- ReqEvent{
|
||||||
|
PeerID: msg.peerID,
|
||||||
|
ReceivedAt: msg.receivedAt,
|
||||||
|
Data: msg.data,
|
||||||
|
}
|
||||||
|
case "EOSE":
|
||||||
|
case "CLOSED":
|
||||||
|
s.closedOnce.Do(func() {
|
||||||
|
s.forwardClosed <- ReqClosed{
|
||||||
|
PeerID: msg.peerID,
|
||||||
|
ReceivedAt: msg.receivedAt,
|
||||||
|
Data: string(msg.data),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit := func(tr terminateReason) {
|
||||||
|
s.preterminate()
|
||||||
|
drain()
|
||||||
|
s.terminate(tr)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case err := <-sent:
|
case err := <-sent:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.terminate(termSendFailed)
|
exit(termSendFailed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case <-s.done:
|
case <-s.done:
|
||||||
s.terminate(termDone)
|
exit(termDone)
|
||||||
return
|
return
|
||||||
case <-s.ctx.Done():
|
case <-s.ctx.Done():
|
||||||
s.send(envelope.EncloseClose(s.id))
|
s.send(envelope.EncloseClose(s.id))
|
||||||
s.terminate(termCancelled)
|
exit(termCancelled)
|
||||||
return
|
return
|
||||||
case <-s.eose:
|
case msg := <-s.inbox:
|
||||||
if s.closeOnEOSE {
|
switch msg.label {
|
||||||
s.send(envelope.EncloseClose(s.id))
|
case "EVENT":
|
||||||
s.terminate(termClosedOnEOSE)
|
s.forwardEvent <- ReqEvent{
|
||||||
|
PeerID: msg.peerID,
|
||||||
|
ReceivedAt: msg.receivedAt,
|
||||||
|
Data: msg.data,
|
||||||
|
}
|
||||||
|
case "EOSE":
|
||||||
|
if s.closeOnEOSE {
|
||||||
|
s.send(envelope.EncloseClose(s.id))
|
||||||
|
exit(termClosedOnEOSE)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "CLOSED":
|
||||||
|
s.closedOnce.Do(func() {
|
||||||
|
s.forwardClosed <- ReqClosed{
|
||||||
|
PeerID: msg.peerID,
|
||||||
|
ReceivedAt: msg.receivedAt,
|
||||||
|
Data: string(msg.data),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
exit(termReceivedClosed)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case <-s.closed:
|
|
||||||
s.terminate(termReceivedClosed)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-18
@@ -15,8 +15,8 @@ func TestRequestManager_Session(t *testing.T) {
|
|||||||
t.Run("sends req on start", func(t *testing.T) {
|
t.Run("sends req on start", func(t *testing.T) {
|
||||||
h := newMockSessionHarness()
|
h := newMockSessionHarness()
|
||||||
s := newSession(
|
s := newSession(
|
||||||
h.ctx, h.id, h.req, h.eose, h.closed, h.done,
|
h.ctx, h.id, h.req, h.inbox, h.events, h.closed, h.closedOnce,
|
||||||
h.send, h.terminate, false, nil)
|
h.done, h.send, h.preterminate, h.terminate, false, nil)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
var got []byte
|
var got []byte
|
||||||
@@ -37,8 +37,8 @@ func TestRequestManager_Session(t *testing.T) {
|
|||||||
send := func([]byte) error { return fmt.Errorf("send failed") }
|
send := func([]byte) error { return fmt.Errorf("send failed") }
|
||||||
|
|
||||||
s := newSession(
|
s := newSession(
|
||||||
h.ctx, h.id, h.req, h.eose, h.closed, h.done,
|
h.ctx, h.id, h.req, h.inbox, h.events, h.closed, h.closedOnce,
|
||||||
send, h.terminate, false, nil)
|
h.done, send, h.preterminate, h.terminate, false, nil)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
Eventually(t, func() bool {
|
Eventually(t, func() bool {
|
||||||
@@ -54,8 +54,8 @@ func TestRequestManager_Session(t *testing.T) {
|
|||||||
t.Run("ignores eose if stream", func(t *testing.T) {
|
t.Run("ignores eose if stream", func(t *testing.T) {
|
||||||
h := newMockSessionHarness()
|
h := newMockSessionHarness()
|
||||||
s := newSession(
|
s := newSession(
|
||||||
h.ctx, h.id, h.req, h.eose, h.closed, h.done,
|
h.ctx, h.id, h.req, h.inbox, h.events, h.closed, h.closedOnce,
|
||||||
h.send, h.terminate, false, nil)
|
h.done, h.send, h.preterminate, h.terminate, false, nil)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
// wait for initial REQ send before proceeding
|
// wait for initial REQ send before proceeding
|
||||||
@@ -68,7 +68,7 @@ func TestRequestManager_Session(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}, "expected initial send")
|
}, "expected initial send")
|
||||||
|
|
||||||
h.eose <- struct{}{}
|
h.inbox <- sessionMessage{label: "EOSE"}
|
||||||
|
|
||||||
Never(t, func() bool {
|
Never(t, func() bool {
|
||||||
select {
|
select {
|
||||||
@@ -83,8 +83,8 @@ func TestRequestManager_Session(t *testing.T) {
|
|||||||
t.Run("sends close on eose if query", func(t *testing.T) {
|
t.Run("sends close on eose if query", func(t *testing.T) {
|
||||||
h := newMockSessionHarness()
|
h := newMockSessionHarness()
|
||||||
s := newSession(
|
s := newSession(
|
||||||
h.ctx, h.id, h.req, h.eose, h.closed, h.done,
|
h.ctx, h.id, h.req, h.inbox, h.events, h.closed, h.closedOnce,
|
||||||
h.send, h.terminate, true, nil)
|
h.done, h.send, h.preterminate, h.terminate, true, nil)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
// drain initial REQ send
|
// drain initial REQ send
|
||||||
@@ -97,7 +97,7 @@ func TestRequestManager_Session(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}, "expected initial REQ send")
|
}, "expected initial REQ send")
|
||||||
|
|
||||||
h.eose <- struct{}{}
|
h.inbox <- sessionMessage{label: "EOSE"}
|
||||||
|
|
||||||
var got []byte
|
var got []byte
|
||||||
Eventually(t, func() bool {
|
Eventually(t, func() bool {
|
||||||
@@ -124,8 +124,8 @@ func TestRequestManager_Session(t *testing.T) {
|
|||||||
t.Run("terminates on done close", func(t *testing.T) {
|
t.Run("terminates on done close", func(t *testing.T) {
|
||||||
h := newMockSessionHarness()
|
h := newMockSessionHarness()
|
||||||
s := newSession(
|
s := newSession(
|
||||||
h.ctx, h.id, h.req, h.eose, h.closed, h.done,
|
h.ctx, h.id, h.req, h.inbox, h.events, h.closed, h.closedOnce,
|
||||||
h.send, h.terminate, false, nil)
|
h.done, h.send, h.preterminate, h.terminate, false, nil)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
// wait for initial req
|
// wait for initial req
|
||||||
@@ -153,8 +153,8 @@ func TestRequestManager_Session(t *testing.T) {
|
|||||||
t.Run("terminates on context cancel", func(t *testing.T) {
|
t.Run("terminates on context cancel", func(t *testing.T) {
|
||||||
h := newMockSessionHarness()
|
h := newMockSessionHarness()
|
||||||
s := newSession(
|
s := newSession(
|
||||||
h.ctx, h.id, h.req, h.eose, h.closed, h.done,
|
h.ctx, h.id, h.req, h.inbox, h.events, h.closed, h.closedOnce,
|
||||||
h.send, h.terminate, false, nil)
|
h.done, h.send, h.preterminate, h.terminate, false, nil)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
Eventually(t, func() bool {
|
Eventually(t, func() bool {
|
||||||
@@ -181,8 +181,8 @@ func TestRequestManager_Session(t *testing.T) {
|
|||||||
t.Run("terminates on closed signal", func(t *testing.T) {
|
t.Run("terminates on closed signal", func(t *testing.T) {
|
||||||
h := newMockSessionHarness()
|
h := newMockSessionHarness()
|
||||||
s := newSession(
|
s := newSession(
|
||||||
h.ctx, h.id, h.req, h.eose, h.closed, h.done,
|
h.ctx, h.id, h.req, h.inbox, h.events, h.closed, h.closedOnce,
|
||||||
h.send, h.terminate, false, nil)
|
h.done, h.send, h.preterminate, h.terminate, false, nil)
|
||||||
go s.run()
|
go s.run()
|
||||||
|
|
||||||
Eventually(t, func() bool {
|
Eventually(t, func() bool {
|
||||||
@@ -194,7 +194,7 @@ func TestRequestManager_Session(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}, "expected initial send")
|
}, "expected initial send")
|
||||||
|
|
||||||
h.closed <- struct{}{}
|
h.inbox <- sessionMessage{label: "CLOSED"}
|
||||||
|
|
||||||
Eventually(t, func() bool {
|
Eventually(t, func() bool {
|
||||||
select {
|
select {
|
||||||
@@ -661,7 +661,7 @@ func TestRequestManager_Query(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRequestManager_Reconnect(t *testing.T) {
|
func _TestRequestManager_Reconnect(t *testing.T) {
|
||||||
t.Run("sessions terminate on disconnect", func(t *testing.T) {
|
t.Run("sessions terminate on disconnect", func(t *testing.T) {
|
||||||
// connect, open two streams
|
// connect, open two streams
|
||||||
// send a disconnect event into the mock events channel
|
// send a disconnect event into the mock events channel
|
||||||
|
|||||||
Reference in New Issue
Block a user