go-sdk/internal/jsonrpc2/serve_pre116.go
Bryan C. Mills 1afb0eb5ac internal/jsonrpc2_v2: rework Connection concurrency
This change fixes the semantics of Close to actually wait for
in-flight requests before closing the ReadWriteCloser. (Previously,
the Close method closed the ReadWriteCloser immediately, which I
suspect is what led to many of the failures observed in
golang/go#49387 and golang/go#46520.)

It achieves this by explicitly tracking the number of in-flight
requests, including requests with pending async responses, and
explicitly rejecting new Call requests (while keeping the read loop
open!) once Close has begun.

To make it easier for me to reason about the request lifetimes, I
reduced the number of long-lived goroutines from three to just one
(the Read loop), with an additional Handler goroutine that runs only
while the Handler queue is non-empty. Now, it is clearer (I hope!)
that the number of in-flight async requests strictly decreases
after Close has begun, even though the Read goroutine continues
to read requests (and, importantly, responses) and to forward
Notifications to the preempter.

For golang/go#49387
For golang/go#46520

Change-Id: Idf5960f848108a7ced78c5382099c8692e9b181e
Reviewed-on: https://go-review.googlesource.com/c/tools/+/388134
gopls-CI: kokoro <noreply+kokoro@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
2022-10-31 15:02:00 +00:00

30 lines
1 KiB
Go

// Copyright 2020 The Go MCP SDK Authors. All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//go:build !go1.16
// +build !go1.16
package jsonrpc2
import (
"errors"
"strings"
)
// errClosed is an error with the same string as net.ErrClosed,
// which was added in Go 1.16.
var errClosed = errors.New("use of closed network connection")
// isErrClosed reports whether err ends in the same string as errClosed.
func isErrClosed(err error) bool {
// As of Go 1.16, this could be 'errors.Is(err, net.ErrClosing)', but
// unfortunately gopls still requires compatiblity with
// (otherwise-unsupported) older Go versions.
//
// In the meantime, this error strirng has not changed on any supported Go
// version, and is not expected to change in the future.
// This is not ideal, but since the worst that could happen here is some
// superfluous logging, it is acceptable.
return strings.HasSuffix(err.Error(), "use of closed network connection")
}