Server-side function object to register request handlers.
The examples below are based on the following .proto file:
syntax = "proto3";
package example.v1;
service Example {
rpc ServerStreaming(Request) returns (stream Response) {}
rpc ClientStreaming(stream Request) returns (Response) {}
rpc BidirectionalStreaming(stream Request) returns (stream Response) {}
rpc Unary(Request) returns (Response) {}
}
message Request {
int32 integer = 1;
}
message Response {
int32 integer = 1;
}
This function helps to ensure that there are enough outstanding calls to request
to match incoming RPCs. It takes a RPC, a Service, a RequestHandler and a CompletionToken. The RequestHandler determines what to do with a client request, it could e.g. spawn a new coroutine to process it. It must also have an associated executor that refers to a agrpc::GrpcContext
. When the client makes a request the RequestHandler is invoked with a agrpc::RepeatedlyRequestContext
- a move-only type that provides a stable address to the grpc::ServerContext
, the request (if any) and the responder that were used when requesting the RPC. It should be kept alive until the RPC is finished. The RequestHandler (or its associated executor [until v1.8.0] / the CompletionToken's completion handler [since v1.8.0]) may also have an associated allocator to control the allocation needed for each request.
agrpc::repeatedly_request
will complete when it was cancelled, the agrpc::GrpcContext
was stopped or the grpc::Server
been shutdown. It will not wait until all outstanding RPCs that are being processed by the RequestHandler have completed.
When using the special CompletionToken created by agrpc::use_sender
the RequestHandler's signature must be:
sender auto operator()(grpc::ServerContext&, Request&, Responder&)
for unary and server-streaming requests and
sender auto operator()(grpc::ServerContext&, Responder&)
otherwise.
For libunifex this is the only available overload of this function.
auto register_client_streaming_handler(example::v1::Example::AsyncService& service,
agrpc::GrpcContext& grpc_context)
{
&example::v1::Example::AsyncService::RequestUnary, service,
[&](grpc::ServerContext&, example::v1::Request&
request,
grpc::ServerAsyncResponseWriter<example::v1::Response>& writer)
{
return unifex::let_value(unifex::just(example::v1::Response{}),
[&](auto& response)
{
response.set_integer(
request.integer());
});
},
}
Execution context based on grpc::CompletionQueue
Definition: grpcContext.hpp:50
constexpr detail::UseSenderFn use_sender
Create sender completion token.
Definition: useSender.hpp:66
constexpr detail::RequestFn request
Start a new RPC.
Definition: rpc.hpp:1493
constexpr detail::FinishFn finish
Finish a RPC.
Definition: rpc.hpp:1529
constexpr detail::RepeatedlyRequestFn repeatedly_request
Register a request handler for a RPC.
Definition: repeatedlyRequest.hpp:146
Another special overload of agrpc::repeatedly_request
can be used by passing a RequestHandler with the following signature:
awaitable auto operator()(grpc::ServerContext&, Request&, Responder&)
for unary and server-streaming requests and
awaitable auto operator()(grpc::ServerContext&, Responder&)
otherwise.
void register_client_streaming_handler(example::v1::Example::AsyncService& service,
agrpc::GrpcContext& grpc_context)
{
&example::v1::Example::AsyncService::RequestClientStreaming, service,
asio::bind_executor(
grpc_context,
[&](grpc::ServerContext&,
grpc::ServerAsyncReader<example::v1::Response, example::v1::Request>&) -> asio::awaitable<void>
{
co_return;
}));
}
The following example shows how to implement a RequestHandler with a custom allocator for simple, high-performance RPC processing:
template <class Executor, class Handler, class Alllocator>
struct AssociatedHandler
{
using executor_type = Executor;
using allocator_type = Alllocator;
Executor executor;
Handler handler;
Alllocator allocator;
AssociatedHandler(Executor executor, Handler handler, Alllocator allocator)
: executor(std::move(executor)), handler(std::move(handler)), allocator(allocator)
{
}
template <class T>
{
std::invoke(handler, std::move(request_context), executor);
}
[[nodiscard]] executor_type get_executor() const noexcept { return executor; }
[[nodiscard]] allocator_type get_allocator() const noexcept { return allocator; }
};
void repeatedly_request_example(example::v1::Example::AsyncService& service,
agrpc::GrpcContext& grpc_context)
{
&example::v1::Example::AsyncService::RequestUnary, service,
[](auto&& request_context, auto&& executor)
{
auto& writer = request_context.responder();
example::v1::Response response;
asio::bind_executor(executor, [c = std::move(request_context)](bool) {}));
},
}
allocator_type get_allocator() noexcept
Get the associated allocator.
Definition: grpcContext.ipp:91
executor_type get_executor() noexcept
Get the associated executor.
Definition: grpcContext.ipp:87
Context passed to the request handler of repeatedly_request.
Definition: repeatedlyRequestContext.hpp:41
auto operator()(detail::ServerMultiArgRequest< RPC, Request, Responder > rpc, Service &service, RequestHandler &&request_handler, CompletionToken &&token={}) const
Overload for unary and server-streaming RPCs.
Definition: repeatedlyRequest.hpp:119
- Parameters
-
request_handler | Any exception thrown by the invocation of the request handler will be rethrown by GrpcContext::run(). Except for the sender version, where the exception will be send to the receiver. |
token | The completion signature is void() . If the token has been created by agrpc::use_sender then the request handler must return a sender. |
Per-Operation Cancellation
All. Upon cancellation, the operation completes after receiving the next request from the client. The next request will still be handled normally.