From 07f7006373f09e63a4359d7e293528ee3cbdb5a0 Mon Sep 17 00:00:00 2001 From: Hein Meling Date: Tue, 13 Oct 2026 02:03:13 +0200 Subject: [PATCH] stream: wait out Connecting before watching for GOAWAY watchGoAway drained a session as soon as the connection was not Ready. Just after the stream opens, the ClientConn can still report Connecting, so a healthy session was drained and ended at once. One-way messages that Send had accepted but gRPC had not yet written were lost. Wait for the connection to leave Connecting before treating a state change as a server GOAWAY. Closes: #364 --- internal/stream/outbound.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/stream/outbound.go b/internal/stream/outbound.go index 63aa404c..7d7acfef 100644 --- a/internal/stream/outbound.go +++ b/internal/stream/outbound.go @@ -180,7 +180,16 @@ func (c *OutboundChannel) open() (*session, error) { // watchGoAway drains s once the connection leaves Ready, which is how the // client observes a server GOAWAY. Pending calls then complete on s while new // requests go to a new stream. It returns when ctx ends. +// +// The connection may still report Connecting just after the stream opens. +// That is not a GOAWAY, so the watcher waits for Ready first; draining then +// would end a healthy session and lose the one-way messages it had accepted. func (c *OutboundChannel) watchGoAway(ctx context.Context, s *session) { + for c.conn.GetState() == connectivity.Connecting { + if !c.conn.WaitForStateChange(ctx, connectivity.Connecting) { + return + } + } for c.conn.GetState() == connectivity.Ready { if !c.conn.WaitForStateChange(ctx, connectivity.Ready) { return