userver: ugrpc::server::GenericServiceBase Class Reference
Loading...
Searching...
No Matches
ugrpc::server::GenericServiceBase Class Referenceabstract

#include <userver/ugrpc/server/generic_service_base.hpp>

Detailed Description

Allows to handle RPCs with dynamic method names.

To use:

  1. inherit from this class in e.g. YourGenericService;
  2. put YourGenericService in a descendent of ServiceComponentBase, e.g. YourGenericServiceComponent

Alternatively, just inherit from GenericServiceBase::Component, with the disadvantage that the service will not be unit-testable.

The API is mainly intended for proxies, where the request-response body is passed unchanged, with settings taken solely from the RPC metadata. In cases where the code needs to operate on the actual messages, serialization of requests and responses is left as an excercise to the user.

Middlewares are customizable and are applied as usual, except that no message hooks are called, meaning that there won't be any logs of messages from the default middleware.

Statically-typed services, if registered, take priority over generic services. It only makes sense to register at most 1 generic service.

Generic gRPC service metrics

Metrics are accounted for "Generic/Generic" fake call name by default. This is the safe choice that avoids potential OOMs. To use the real dynamic RPC name for metrics, use CallAnyBase::SetMetricsCallName in conjunction with CallAnyBase::GetCallName.

Warning
If the microservice serves as a proxy and has untrusted clients, it is a good idea to avoid having per-RPC metrics to avoid the situations where an upstream client can spam various RPCs with non-existent names, which leads to this microservice spamming RPCs with non-existent names, which leads to creating storage for infinite metrics and causes OOM.

Example GenericServiceBase usage with known message types

constexpr std::string_view kSayHelloCallName =
"sample.ugrpc.UnitTestService/SayHello";
class SampleGenericService final : public ugrpc::server::GenericServiceBase {
public:
void Handle(Call& call) override {
EXPECT_EQ(call.GetCallName(), kSayHelloCallName);
grpc::ByteBuffer request_bytes;
ASSERT_TRUE(call.Read(request_bytes));
sample::ugrpc::GreetingRequest request;
if (!ugrpc::ParseFromByteBuffer(std::move(request_bytes), request)) {
call.FinishWithError(grpc::Status{grpc::StatusCode::INVALID_ARGUMENT,
"Failed to parse request"});
return;
}
sample::ugrpc::GreetingResponse response;
response.set_name("Hello " + request.name());
call.WriteAndFinish(ugrpc::SerializeToByteBuffer(response));
}
};

For a more complete sample, see grpc_generic_api.

Definition at line 57 of file generic_service_base.hpp.

Public Types

using Component = impl::ServiceComponentBase<GenericServiceBase>
 
using Call = BidirectionalStream<grpc::ByteBuffer, grpc::ByteBuffer>
 

Public Member Functions

 GenericServiceBase (GenericServiceBase &&)=delete
 
GenericServiceBaseoperator= (GenericServiceBase &&)=delete
 
virtual void Handle (Call &call)=0
 Override this method in the derived class to handle all RPCs. RPC name can be obtained through CallAnyBase::GetCallName.
 

Member Typedef Documentation

◆ Call

using ugrpc::server::GenericServiceBase::Call = BidirectionalStream<grpc::ByteBuffer, grpc::ByteBuffer>

Definition at line 64 of file generic_service_base.hpp.

◆ Component

Inherits from both GenericServiceBase and ServiceComponentBase. Allows to implement the service directly in a component. The disadvantage is that such services are not unit-testable.

Definition at line 62 of file generic_service_base.hpp.

Member Function Documentation

◆ Handle()

virtual void ugrpc::server::GenericServiceBase::Handle ( Call & call)
pure virtual

Override this method in the derived class to handle all RPCs. RPC name can be obtained through CallAnyBase::GetCallName.

Note
RPCs of all kinds (including unary RPCs) are represented using BidirectionalStream API.
The implementation of the method should call Finish or FinishWithError, otherwise the server will respond with an "internal server error" status.

The documentation for this class was generated from the following file: