Skip to content

Inline request/reply over the Wolverine.Grpc transport (GH-2967)#2995

Merged
jeremydmiller merged 1 commit into
mainfrom
feat-2967-grpc-inline-request-reply
May 31, 2026
Merged

Inline request/reply over the Wolverine.Grpc transport (GH-2967)#2995
jeremydmiller merged 1 commit into
mainfrom
feat-2967-grpc-inline-request-reply

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Closes #2967. Companion to #2966/#2990 (HTTP inline request/reply), built on the shared IInlineRequestReplyEndpoint / MessageRoute.For infrastructure that merged with #2990.

What

InvokeAsync<T> routed to a gRPC endpoint now reads the reply straight off a new unary Call(WolverineMessage) returns (WolverineMessage) RPC — no ReplyListener, no listening endpoint on the sender, no TaskCompletionSource reply choreography. gRPC's unary response slot carries the reply envelope in the same exchange.

How

  • wolverine.proto — new rpc Call(WolverineMessage) returns (WolverineMessage); request carries the serialized request envelope, response carries the serialized reply (which may be a FailureAcknowledgement).
  • GrpcEndpoint now implements IInlineRequestReplyEndpoint, so MessageRoute.For(...) selects the InlineReplyMessageRoute subclass — no runtime if/then (the same shape Jeremy asked for in Optimized inline request/reply over the Wolverine.Http transport (GH-2966) #2990). InvokeRemoteAsync serializes the request, calls the unary RPC over a cached GrpcChannel/client, and deserializes the reply. An RpcException (transport-level failure) maps to a FailureAcknowledgement reply so the caller still gets the usual WolverineRequestReplyException.
  • Receiver Call handler mirrors the HTTP transport executor: deserialize the request, set ResponseType from ReplyRequested, run executor.InvokeInlineAsync (flushing the outbox before the response), and return Envelope.Response. Handler failures / missing handlers come back as a FailureAcknowledgement reply. MessageTracking.MessageSucceeded fires on every success path so tracked sessions quiesce.

Tests

  • New inline_request_reply_grpc — happy path asserts the reply is read off the gRPC response slot (sender has no reply listener, so a pass proves the inline path); failure path asserts a handler throw surfaces as WolverineRequestReplyException.
  • GrpcTransportCompliance.can_request_reply passes unchanged against the inline path.
  • Full gRPC suite: 218/218 green. dotnet build wolverine.slnx -c Release clean.

🤖 Generated with Claude Code

InvokeAsync<T> routed to a gRPC endpoint now reads the reply off a new
unary Call(WolverineMessage) RPC — no ReplyListener, no listening
endpoint on the sender. GrpcEndpoint implements IInlineRequestReplyEndpoint
so MessageRoute.For selects the InlineReplyMessageRoute (shared infra from
GH-2966), with no runtime if/then.

The receiver-side Call handler mirrors the HTTP transport executor:
deserialize the request envelope, set ResponseType from ReplyRequested,
run executor.InvokeInlineAsync (flushing the outbox before the response),
and return Envelope.Response. Handler failures and missing handlers come
back as a FailureAcknowledgement reply (sender rethrows
WolverineRequestReplyException); RpcException transport failures map the
same way. MessageSucceeded fires on every success path so tracked
sessions quiesce.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@jeremydmiller jeremydmiller merged commit 996a9cf into main May 31, 2026
23 checks passed
This was referenced Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Optimized inline request/reply over the Wolverine.Grpc sender transport

1 participant