Skip to content

Commit

Permalink
feat: Change CoroutineTraits::Rebind to CoroutineTraits::ReturnType i…
Browse files Browse the repository at this point in the history
…n register_coroutine_rpc_handler and add documentation
  • Loading branch information
Tradias committed Nov 27, 2024
1 parent 79fe6c4 commit db6d8cb
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 17 deletions.
2 changes: 1 addition & 1 deletion doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Feature overview, installation and performance benchmark can be found on [github
* Main workhorses of this library: `agrpc::GrpcContext`, `agrpc::GrpcExecutor`.
* Asynchronous gRPC clients: [cheat sheet](md_doc_2client__rpc__cheat__sheet.html), `agrpc::ClientRPC`,
* Asynchronous gRPC servers: [cheat sheet](md_doc_2server__rpc__cheat__sheet.html), `agrpc::ServerRPC`, `agrpc::register_awaitable_rpc_handler`,
`agrpc::register_yield_rpc_handler`, `agrpc::register_sender_rpc_handler`, `agrpc::register_callback_rpc_handler`
`agrpc::register_yield_rpc_handler`, `agrpc::register_sender_rpc_handler`, `agrpc::register_callback_rpc_handler`, `agrpc::register_coroutine_rpc_handler`
* GRPC Timer: `agrpc::Alarm`
* Combining GrpcContext and `asio::io_context`: `agrpc::run`, `agrpc::run_completion_queue`
* Faster, drop-in replacement for gRPC's [DefaultHealthCheckService](https://github.com/grpc/grpc/blob/v1.50.1/src/cpp/server/health/default_health_check_service.h): `agrpc::HealthCheckService`
Expand Down
7 changes: 4 additions & 3 deletions example/helper/coro_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@

namespace example
{
template <class Executor = boost::asio::any_io_executor>
/* [asio-coro-traits] */
template <class Executor = boost::asio::any_io_executor, class Allocator = std::allocator<void>>
struct AsioCoroTraits
{
template <class U>
using Rebind = boost::asio::experimental::coro<void, U, Executor>;
using ReturnType = boost::asio::experimental::coro<void, void, Executor, Allocator>;

template <class RPCHandler, class CompletionHandler>
static boost::asio::deferred_t completion_token(RPCHandler&, CompletionHandler&)
Expand All @@ -42,6 +42,7 @@ struct AsioCoroTraits
boost::asio::detached);
}
};
/* [asio-coro-traits] */
} // namespace example

#endif // AGRPC_HELPER_CORO_TRAITS_HPP
3 changes: 1 addition & 2 deletions src/agrpc/detail/coroutine_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ struct CoroutineTraits;
template <class T, class Executor>
struct CoroutineTraits<asio::awaitable<T, Executor>>
{
template <class U>
using Rebind = asio::awaitable<U, Executor>;
using ReturnType = asio::awaitable<void, Executor>;

template <class RPCHandler, class CompletionHandler>
static asio::use_awaitable_t<Executor> completion_token(RPCHandler&, CompletionHandler&)
Expand Down
3 changes: 1 addition & 2 deletions src/agrpc/detail/register_coroutine_rpc_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@ struct RegisterCoroutineRPCHandlerOperation
struct Type : detail::RegisterRPCHandlerOperationAsioBase<ServerRPC, RPCHandler, CompletionHandler>
{
using Base = detail::RegisterRPCHandlerOperationAsioBase<ServerRPC, RPCHandler, CompletionHandler>;
using Awaitable = typename CoroTraits::ReturnType;
using typename Base::Allocator;
using typename Base::RefCountGuard;
using typename Base::ServerRPCExecutor;
using typename Base::Service;

using Awaitable = typename CoroTraits::template Rebind<void>;

template <class Ch>
Type(const ServerRPCExecutor& executor, Service& service, RPCHandler&& rpc_handler, Ch&& completion_handler)
: Base(executor, service, static_cast<RPCHandler&&>(rpc_handler), static_cast<Ch&&>(completion_handler),
Expand Down
2 changes: 1 addition & 1 deletion src/agrpc/register_awaitable_rpc_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ AGRPC_NAMESPACE_BEGIN()
* first argument and `ServerRPC::Request&` as second argument (only for unary and server-streaming rpcs). The ServerRPC
* is automatically cancelled at the end of the rpc handler if `finish()` was not called earlier. The return value of
* the rpc handler is `co_spawn`ed in a manner similar to:
* `asio::co_spawn(asio::get_associated_executor(completion_handler, executor), rpc_handler())`, where
* `asio::co_spawn(asio::get_associated_executor(completion_handler, executor), rpc_handler)`, where
* `completion_handler` is created from `token` and `executor` the first argument passed to this function.
*
* This asynchronous operation runs forever unless it is cancelled, the rpc handler throws an exception or the server is
Expand Down
22 changes: 22 additions & 0 deletions src/agrpc/register_coroutine_rpc_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,29 @@ AGRPC_NAMESPACE_BEGIN()
/**
* @brief (experimental) Register a coroutine rpc handler for the given method
*
* The rpc handler will be invoked for every incoming request of this gRPC method. It must take `ServerRPC&` as
* first argument and `ServerRPC::Request&` as second argument (only for unary and server-streaming rpcs). The ServerRPC
* is automatically cancelled at the end of the rpc handler if `finish()` was not called earlier. The return value of
* the rpc handler is `co_spawn`ed in a manner similar to:
* `CoroutineTraits::co_spawn(executor, rpc_handler, completion_handler, function)`, where
* `completion_handler` is created from `token`, `executor` the first argument passed to this function and `function`,
* when invoked, starts waiting for the next rpc. Any arguments passed to `function` will be prepended to the call of
* the rpc handler. The return type of `function` is `CoroutineTraits::ReturnType`, which must be a coroutine, and
* `CoroutineTraits::completion_token` must produce an Asio compatible [completion
* token](https://www.boost.org/doc/libs/1_86_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.completion_tokens_and_handlers)
* that, when used to initiate an asynchronous operation, returns an awaitable.
*
* This asynchronous operation runs forever unless it is cancelled, the rpc handler throws an exception or the server is
* shutdown
* ([grpc::Server::Shutdown](https://grpc.github.io/grpc/cpp/classgrpc_1_1_server_interface.html#a6a1d337270116c95f387e0abf01f6c6c)
* is called). At which point it invokes the completion handler (passing forward the exception thrown by the request
* handler, if any) after all coroutines produced by invoking the rpc handler complete.
*
* @tparam ServerRPC An instantiation of `agrpc::ServerRPC`
* @tparam CoroutineTraits A class that provides functions for spawning the coroutine of each rpc. Example:
*
* @snippet coro_traits.hpp asio-coro-traits
*
* @param executor The executor used to handle each rpc
* @param service The service associated with the gRPC method of the ServerRPC
* @param rpc_handler A callable that produces a coroutine. The coroutine's return value is ignored.
Expand Down
10 changes: 4 additions & 6 deletions test/src/test_server_rpc_20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,11 +558,10 @@ TEST_CASE_FIXTURE(ServerRPCAwaitableTest<test::ServerStreamingServerRPC>,
#endif

#ifdef AGRPC_TEST_ASIO_HAS_CORO
template <class Yield, class Return, class Executor>
template <class Executor>
struct CoroTraits
{
template <class U>
using Rebind = asio::experimental::coro<Yield, U, Executor>;
using ReturnType = asio::experimental::coro<void, void, Executor>;

template <class RPCHandler, class CompletionHandler>
static asio::deferred_t completion_token(RPCHandler&, CompletionHandler&)
Expand Down Expand Up @@ -608,7 +607,7 @@ TEST_CASE_FIXTURE(ServerRPCAwaitableTest<test::ClientStreamingServerRPC>,
}
};
asio::io_context io_context{1};
agrpc::register_coroutine_rpc_handler<ServerRPC, CoroTraits<void, void, Exec>>(
agrpc::register_coroutine_rpc_handler<ServerRPC, CoroTraits<Exec>>(
get_executor(), service, Handler{}, asio::bind_executor(io_context.get_executor(), test::RethrowFirstArg{}));
std::thread t{[&]
{
Expand All @@ -633,8 +632,7 @@ TEST_CASE_FIXTURE(ServerRPCAwaitableTest<test::ClientStreamingServerRPC>,
#ifdef AGRPC_TEST_HAS_BOOST_COBALT
struct BoostCobaltTraits
{
template <class U>
using Rebind = boost::cobalt::task<U>;
using ReturnType = boost::cobalt::task<void>;

template <class RPCHandler, class CompletionHandler>
static boost::cobalt::use_op_t completion_token(RPCHandler&, CompletionHandler&)
Expand Down
3 changes: 1 addition & 2 deletions test/src/test_unifex_20.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,7 @@ TEST_CASE_FIXTURE(test::ExecutionGrpcContextTest, "unifex Waiter: initiate alarm
#if defined(AGRPC_TEST_ASIO_HAS_CORO) && !UNIFEX_NO_COROUTINES
struct UnifexCoroutineTraits
{
template <class U>
using Rebind = unifex::task<U>;
using ReturnType = unifex::task<void>;

template <class RPCHandler, class CompletionHandler>
static auto completion_token(RPCHandler&, CompletionHandler&)
Expand Down

0 comments on commit db6d8cb

Please sign in to comment.