From bf8fe04036eb93a53c06d7682fc4316da3e5cd24 Mon Sep 17 00:00:00 2001 From: Keegan Carruthers-Smith Date: Thu, 10 Sep 2026 09:43:30 +0200 Subject: [PATCH] docs/conn: clarify ordering guarantees for bidirectional calls (#105) Users can otherwise mistake transport ordering for application-level synchronization and attempt blocking calls from the synchronous read loop. --- async.go | 3 ++- conn.go | 4 +++- jsonrpc2.go | 10 ++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/async.go b/async.go index bc8a370..6cbdadd 100644 --- a/async.go +++ b/async.go @@ -3,7 +3,8 @@ package jsonrpc2 import "context" // AsyncHandler wraps a Handler such that each request is handled in its own -// goroutine. It is a convenience wrapper. +// goroutine. Handlers may therefore start or finish in a different order than +// requests are received. It is a convenience wrapper. func AsyncHandler(h Handler) Handler { return asyncHandler{h} } diff --git a/conn.go b/conn.go index a9b14ac..1e29546 100644 --- a/conn.go +++ b/conn.go @@ -156,7 +156,9 @@ func (c *Conn) Notify(ctx context.Context, method string, params interface{}, op return err } -// Reply sends a successful response with a result. +// Reply sends a successful response with a result. It returns after writing +// the response to the ObjectStream; it does not wait for the peer to receive or +// process the response. func (c *Conn) Reply(ctx context.Context, id ID, result interface{}) error { resp := &Response{ID: id} if err := resp.SetResult(result); err != nil { diff --git a/jsonrpc2.go b/jsonrpc2.go index 7d3e132..8c145f2 100644 --- a/jsonrpc2.go +++ b/jsonrpc2.go @@ -59,10 +59,12 @@ const ( // Handler handles JSON-RPC requests and notifications. type Handler interface { - // Handle is called to handle a request. No other requests are handled until - // it returns. If you do not require strict ordering behavior of received - // RPCs, it is suggested to wrap your handler in AsyncHandler. The context - // is automatically canceled when the connection closes. + // Handle is called to handle a request. While it is running, the connection + // does not process any other requests or responses. A handler that waits for + // a call's response must therefore run asynchronously. If you do not require + // strict ordering behavior of received RPCs, it is suggested to wrap your + // handler in AsyncHandler. The context is automatically canceled when the + // connection closes. Handle(context.Context, *Conn, *Request) }