Drain the handler queues before stopping the handlers on shutdown (closes #69)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
Shutdown stopped the handlers before the streamer, so the updates still on the handler queues reached handlers that no longer wrote them. It now stops the streamer first. Streamer.Stop puts the STATE messages it holds for a full queue on that queue, closes the queues and returns once every worker has handed its handler everything on its queue; then each handler writes what it holds. PeeringHandler.Stop now waits for its loop's final write instead of racing it. Streamer.SetURL lets the shutdown test read from a local server. Model: opus-5-5
This commit is contained in:
@@ -255,6 +255,24 @@ func TestHeldStateMessagesKeepTheirPlaceInTheQueue(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// takeAll takes the messages off queue, as a handler's worker would, and sends
|
||||
// them on the returned channel once queue is closed.
|
||||
func takeAll(queue chan *ristypes.RISMessage) chan []*ristypes.RISMessage {
|
||||
taken := make(chan []*ristypes.RISMessage, 1)
|
||||
|
||||
go func() {
|
||||
var msgs []*ristypes.RISMessage
|
||||
|
||||
for msg := range queue {
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
|
||||
taken <- msgs
|
||||
}()
|
||||
|
||||
return taken
|
||||
}
|
||||
|
||||
// newStreamerWithFullStateQueue returns a streamer reading from url with one
|
||||
// handler, a stateHandler whose queue is full.
|
||||
func newStreamerWithFullStateQueue(url string) *Streamer {
|
||||
@@ -306,20 +324,23 @@ func TestOtherHandlersKeepReceivingWhileAStateMessageIsHeld(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestStopReturnsAtOnceWithStateMessagesHeld has the server send two STATE
|
||||
// messages and hold the response open while the queue of the handler that
|
||||
// wants them is full. Stop must return at once and end the stream.
|
||||
func TestStopReturnsAtOnceWithStateMessagesHeld(t *testing.T) {
|
||||
// TestStopQueuesTheHeldStateMessages has the server send two STATE messages
|
||||
// and an UPDATE and hold the response open while the queue of the handler that
|
||||
// wants STATE messages is full, so both are held. Stop must put both on the
|
||||
// queue, after the messages already on it, before it closes the queue, and
|
||||
// must end the stream.
|
||||
func TestStopQueuesTheHeldStateMessages(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
lines = 2
|
||||
held = 2
|
||||
lines = held + 1
|
||||
maxWait = 5 * time.Second
|
||||
)
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = io.WriteString(w, stateDownLine+stateDownLine)
|
||||
_, _ = io.WriteString(w, stateDownLine+stateDownLine+updateLine)
|
||||
|
||||
flush(w)
|
||||
<-r.Context().Done()
|
||||
@@ -328,7 +349,7 @@ func TestStopReturnsAtOnceWithStateMessagesHeld(t *testing.T) {
|
||||
|
||||
s := newStreamerWithFullStateQueue(srv.URL)
|
||||
// The raw handler sees each line before the read loop hands it to the
|
||||
// queues, so once it has seen the second line, the first is held.
|
||||
// queues, so once it has seen the UPDATE, both STATE messages are held.
|
||||
linesSeen := make(chan struct{}, lines)
|
||||
|
||||
s.RegisterRawHandler(func(string) { linesSeen <- struct{}{} })
|
||||
@@ -350,6 +371,9 @@ func TestStopReturnsAtOnceWithStateMessagesHeld(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// No worker runs here: the test takes from the full queue in its place.
|
||||
queue := s.handlers[0].queue
|
||||
taken := takeAll(queue)
|
||||
stopped := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
@@ -364,6 +388,20 @@ func TestStopReturnsAtOnceWithStateMessagesHeld(t *testing.T) {
|
||||
maxWait)
|
||||
}
|
||||
|
||||
// Stop has closed the queue, so takeAll is done or about to be.
|
||||
msgs := <-taken
|
||||
if len(msgs) != cap(queue)+held {
|
||||
t.Fatalf("%d messages came off the queue, want the %d on it and the "+
|
||||
"%d held", len(msgs), cap(queue), held)
|
||||
}
|
||||
|
||||
for _, msg := range msgs[cap(queue):] {
|
||||
if msg.Peer != stateDownPeer || msg.State != ristypes.StateDown {
|
||||
t.Errorf("message after those on the queue has peer %q, state %q; "+
|
||||
"want the down from %s", msg.Peer, msg.State, stateDownPeer)
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-streamErr:
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
|
||||
Reference in New Issue
Block a user