Skip to content

Add unary-first SDK-native gRPC client transport on Restlet - #1563

Merged
jlouvel merged 4 commits into
3.0from
feat/rpc-r3-grpc
Oct 31, 2026
Merged

jlouvel merged 4 commits into
3.0from
feat/rpc-r3-grpc

Conversation

@jlouvel

@jlouvel jlouvel commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add unary, plaintext gRPC client support over a borrowed Restlet HTTP/2 connector, reusing the shared Restlet/Netty engine rather than introducing a second production HTTP stack.

  • Add org.restlet.ext.grpc using grpc-java 1.85.1 native channel, framing, metadata, deadline and status machinery.
  • Bound messages, concurrent calls and call duration; preserve borrowed connector and callback-executor ownership.
  • Reject unsupported streaming, request compression and mismatched per-call authority explicitly.
  • Cover malformed responses, cancellation, disconnect recovery, message limits, shared-connector ownership, and shutdown races.
  • Verify packaged named-module consumption with the SDK network transport excluded.

Validation

Validated in a source-identical worktree outside the IDE workspace to avoid incremental compiler output interference:

  • Full core verify: 2,262 tests, zero failures/errors, one skip; 82.25% instruction coverage against the unchanged 80% gate.
  • Focused core lifecycle regressions: 13 tests passed.
  • Extension verify: 33 tests, zero failures/errors/skips; 91.71% instruction coverage against the unchanged 80% gate.
  • Dependency convergence, compiler warnings-as-errors, Spotless, SpotBugs, Javadoc and packaging passed. Extension SpotBugs has zero findings; core's existing ratchet is unchanged.
  • Separate named-module consumer test passed using packaged core/extension JARs without grpc-netty.

Scope and dependency

Stacked on feat/rpc-r1-foundations at afe0801dd364f27e2ab7d4b53f2364cb65bf44fd.

This is unary and explicit plaintext support only, not full production gRPC transport parity. TLS/mTLS, streaming methods, retries, full load-balancing/reconnect conformance, keepalive and physical connection controls remain out of scope. grpc-netty-shaded is an interop-test peer only; production HTTP I/O remains Restlet-owned.

The public diff contains only the extension, root build wiring and release notes. Private design documentation and local validation artifacts are excluded.

@jlouvel
jlouvel requested a review from thboileau October 24, 2026 13:02
@jlouvel

jlouvel commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

@thboileau Could you review this PR, part of a stack of three preparation for foundation for support of gRPC, MCP and Smithy on top of Restlet 3 / Netty 4.2 reusing a maximum of the official SDKs/libraries?

@jlouvel
jlouvel requested a balanced review from Copilot October 30, 2026 14:50
@jlouvel jlouvel self-assigned this Oct 30, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Deframer failures can leave HTTP exchanges and workers blocked indefinitely, while cancelled deadline tasks remain queued, creating critical worker-retention and heap-growth risks.

4 open issues
What changed in this PR

Adds an experimental unary gRPC client extension that uses grpc-java’s channel machinery over Restlet’s existing HTTP/2 connector, without adding a production SDK network transport.

Changes:

  • Adds explicit plaintext configuration, message and concurrency limits, deadlines, and borrowed-resource lifecycle handling.
  • Implements SDK framing, metadata, status handling, and cancellation over Restlet HTTP exchanges.
  • Adds interoperability, malformed-response, lifecycle, and named-module tests, plus build wiring and release notes.
File Description
pom.xml Registers the extension and pins the grpc-java version.
org.restlet.ext.grpc/​src/​test/​java/​org/​restlet/​ext/​grpc/​internal/​RestletClientStreamTestCase.java Tests shutdown before listener installation and once-only cleanup.
org.restlet.ext.grpc/​src/​test/​java/​org/​restlet/​ext/​grpc/​GrpcModuleTestCase.java Tests named-module consumption without grpc-netty.
org.restlet.ext.grpc/​src/​test/​java/​org/​restlet/​ext/​grpc/​GrpcHttpValidationTestCase.java Tests malformed responses, message limits, and recovery.
org.restlet.ext.grpc/​src/​test/​java/​org/​restlet/​ext/​grpc/​GrpcClientAdapterTestCase.java Tests SDK interoperability, configuration, cancellation, and resource ownership.
org.restlet.ext.grpc/​src/​main/​java/​org/​restlet/​ext/​grpc/​internal/​RestletTransportFactory.java Manages logical transports, call admission, and owned executors.
org.restlet.ext.grpc/​src/​main/​java/​org/​restlet/​ext/​grpc/​internal/​RestletClientStream.java Bridges SDK-framed unary calls to Restlet HTTP/2 exchanges.
org.restlet.ext.grpc/​src/​main/​java/​org/​restlet/​ext/​grpc/​internal/​GuardedClientStream.java Enforces message limits and converts framing failures to call status.
org.restlet.ext.grpc/​src/​main/​java/​org/​restlet/​ext/​grpc/​GrpcClientAdapter.java Exposes channel configuration and lifecycle management.
org.restlet.ext.grpc/​src/​main/​java/​module-info.java Declares module dependencies and exports the public adapter package.
org.restlet.ext.grpc/​pom.xml Defines production and test dependencies for the extension.
changes.md Documents the experimental transport and its limitations.

Review effort: Balanced

@jlouvel
jlouvel force-pushed the feat/rpc-r1-foundations branch from afe0801 to b296e89 Compare October 31, 2026 06:37
@jlouvel
jlouvel force-pushed the feat/rpc-r1-foundations branch from b296e89 to 45ffe88 Compare October 31, 2026 21:19
Base automatically changed from feat/rpc-r1-foundations to 3.0 October 31, 2026 21:36
jlouvel and others added 4 commits October 31, 2026 17:38
Reuse a borrowed Restlet HTTP/2 connector with grpc-java 1.85.1. Bound unary messages and calls, preserve SDK lifecycle semantics, and verify packaged named-module consumption.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Jerome Louvel <374450+jlouvel@users.noreply.github.com>
A deframing failure, such as an unsupported grpc-encoding, now aborts the
underlying HTTP exchange so that its worker does not stay blocked reading
an unfinished response body.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Register the cap first so that it runs last and clamps the call options
passed to the transport, even if an interceptor sets a longer deadline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@jlouvel
jlouvel merged commit 564bab8 into 3.0 Oct 31, 2026
3 of 4 checks passed
@jlouvel
jlouvel deleted the feat/rpc-r3-grpc branch October 31, 2026 21:58
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.

2 participants