Skip to content

Add asynchronous RPC support to asio_rpc, co20_rpc and coro_rpc backends#88

Merged
dallison merged 3 commits into
mainfrom
rpc_all_async
Jun 10, 2026
Merged

Add asynchronous RPC support to asio_rpc, co20_rpc and coro_rpc backends#88
dallison merged 3 commits into
mainfrom
rpc_all_async

Conversation

@dallison

Copy link
Copy Markdown
Owner

Summary

Ports the asynchronous RPC pipeline (previously added to the co::Coroutine rpc/ backend in #86) to the three remaining C++ RPC backends — asio_rpc (Boost.Asio stackful yield_context), co20_rpc (C++20 stackless co::Coroutine runtime) and coro_rpc (C++20 boost::asio::awaitable).

  • Adds a backend-agnostic rpc_internal::SharedPtrPipeBase (rpc/common/shared_ptr_pipe_base.h) that owns the non-blocking pipe fds, raw read/write, and std::shared_ptr (de)serialization with in-transit reference semantics. Each backend wraps it with its own async SharedPtrPipe<T>:
    • asio_rpc: Read/Write suspend via yield_context.
    • co20_rpc: Read is a co20::ValueTask<absl::Status> with a shared_ptr out-param (ValueTask needs a default-constructible type); Write is synchronous and non-blocking.
    • coro_rpc: Read is awaited and returns awaitable<StatusOr<shared_ptr>>; Write is synchronous and non-blocking.
  • Each server gains internal::ReplyItem/ReplyQueue and RegisterMethodAsync; the existing synchronous RegisterMethod overloads now delegate to the async path.
  • Each server's single method coroutine is replaced by a two-coroutine pipeline: a request coroutine that invokes the (possibly async) handler whose reply/error callbacks enqueue into the pipe, and a response coroutine that drains the pipe and publishes responses.
  • Adds a CallAsyncMethod server test per backend exercising a handler that suspends (timer/sleep) before replying.
  • Build coverage: Bazel targets for the new pipes, plus new asio_rpc/, co20_rpc/ and coro_rpc/ CMakeLists.txt files. asio_rpc and coro_rpc are gated on SUBSPACE_ASIO_RPC (where Boost is fetched); co20_rpc on SUBSPACE_CO20_RPC.

Test plan

  • bazelisk test //rpc/... //asio_rpc/... //co20_rpc/... //coro_rpc/... — all 12 tests pass.
  • CMake builds and ctest pass for asio_rpc, co20_rpc and coro_rpc backends locally.
  • CI green.

dallison added 3 commits June 10, 2026 13:46
Mirror the co::Coroutine async RPC feature for the Boost.Asio (stackful
yield_context) backend.

- Add backend-agnostic rpc/common/shared_ptr_pipe_base.h providing pipe fd
  management, non-blocking byte transfer primitives, and the shared_ptr
  in-transit reference codec, so co20_rpc/coro_rpc can reuse it later.
- Add asio_rpc/common/shared_ptr_pipe.h: a SharedPtrPipe<T> driven by
  boost::asio::yield_context built on the shared base.
- Add RegisterMethodAsync, ReplyItem/ReplyQueue, and split the non-streaming
  method handling into SessionRequestCoroutine + SessionResponseCoroutine
  communicating over the pipe. The synchronous RegisterMethod overloads now
  delegate to the async path.
- Add a CallAsyncMethod server test.
- Add a CMake build for asio_rpc behind the new SUBSPACE_ASIO_RPC option
  (default on, auto-disabled when cross-compiling), fetching Boost via
  FetchContent.
Port the async RPC feature to the C++20 stackless coroutine (co20) backend,
reusing the backend-agnostic rpc/common/shared_ptr_pipe_base.h.

- Add co20_rpc/common/shared_ptr_pipe.h: a SharedPtrPipe<T> with a co20
  ValueTask Read (suspends on the pipe via co20::Wait, reports shutdown as a
  CancelledError) and a synchronous non-blocking Write. Read yields its value
  through an out parameter because co20::ValueTask<T> requires T to be
  default-constructible (absl::StatusOr is not).
- Add RegisterMethodAsync, ReplyItem/ReplyQueue, and split the non-streaming
  method handling into SessionRequestCoroutine + SessionResponseCoroutine
  communicating over the pipe. The synchronous RegisterMethod overloads now
  delegate to the async path.
- Add a CallAsyncMethod server test.
- Add a CMake build for co20_rpc behind the new SUBSPACE_CO20_RPC option
  (default on, skipped when cross-compiling without the host plugin). co20
  targets are compiled as C++20.
- Fix a generated-stub header collision in both the asio_rpc and co20_rpc
  CMake builds: the rpc/ co-flavored "rpc/proto/rpc_test.subspace.*.h" under
  ${CMAKE_BINARY_DIR} was shadowing the backend-flavored stubs, so prepend each
  backend's gen root to the directory include path.
Port the async RPC pipeline to the C++20 boost::asio::awaitable backend,
matching the asio_rpc and co20_rpc implementations.

- Add coro_rpc::SharedPtrPipe<T> (coro_rpc/common/shared_ptr_pipe.h) on top
  of the backend-agnostic rpc_internal::SharedPtrPipeBase, with an awaited
  Read returning awaitable<StatusOr<shared_ptr>> and a synchronous,
  non-blocking Write (a coro handler's reply callback cannot co_await).
- Add internal::ReplyItem/ReplyQueue and RegisterMethodAsync; the existing
  synchronous RegisterMethod overloads now delegate to the async path.
- Replace SessionMethodCoroutine with a two-coroutine pipeline:
  SessionRequestCoroutine invokes the (possibly async) handler whose
  reply/error callbacks enqueue into the pipe, and SessionResponseCoroutine
  drains the pipe and publishes responses.
- Add a CallAsyncMethod server test exercising an async handler that
  suspends on a timer before replying.
- Wire the new pipe and dependencies into Bazel and add coro_rpc/CMakeLists.txt
  (C++20, Boost.Asio, rpc_style=coro), gated on SUBSPACE_ASIO_RPC.

All Bazel and CMake tests pass across rpc, asio_rpc, co20_rpc and coro_rpc.
@dallison dallison merged commit e10beb9 into main Jun 10, 2026
34 checks passed
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.

1 participant