Volo Release 0.3.0
Projects:
In Volo 0.3.0 version, in addition to regular bugfixes, we also brought several important features.
Service Trait refactoring
In version 0.3.0 of Volo, we refactored Service
Trait to make the implementation of Service
Trait easier and provide more flexibility.
Specifically, we changed the definition of Service
Trait from:
pub trait Service<Cx, Request> {
/// Responses given by the service.
type Response;
/// Errors produced by the service.
type Error;
/// The future response value.
type Future<'cx>: Future<Output = Result<Self::Response, Self::Error>> + Send + 'cx
where
Cx: 'cx,
Self: 'cx;
/// Process the request and return the response asynchronously.
fn call<'cx, 's>(&'s mut self, cx: &'cx mut Cx, req: Request) -> Self::Future<'cx>
where
's: 'cx;
}
changed to:
pub trait Service<Cx, Request> {
/// Responses given by the service.
type Response;
/// Errors produced by the service.
type Error;
/// The future response value.
type Future<'cx>: Future<Output = Result<Self::Response, Self::Error>> + Send + 'cx
where
Cx: 'cx,
Self: 'cx;
/// Process the request and return the response asynchronously.
fn call<'cx, 's>(&'s self, cx: &'cx mut Cx, req: Request) -> Self::Future<'cx>
where
's: 'cx;
}
The most obvious change is that the self parameter of the Service Trait method call() is changed from &mut self
to &self
. The purpose of this is that if we relied on &mut self
before, we have to clone to take ownership before calling, and we need Service
users to ensure that the overhead of Clone is low; in fact, this clone is completely unnecessary, and this decision should be handed over to the user to decide. If there is a need to change the internal state, they can lock it internally or use atomic, which can save the cost of cloning.
gRPC multi-Service support
In this version, we also support the scenario where the gRPC server supports multiple Services at the same time, and each Service can have its own layer; of course, the Server can also have a globally valid layer.
If a middleware needs to perceive the specific type of Request / Response and process it, or only for a single Service, it can be added as the Service’s own layer.
This is a breaking change. Users of previous versions may need to modify the code. Specifically, it needs to change from this:
#[volo::main]
async fn main() {
let addr: SocketAddr = "[::]:8080".parse().unwrap();
let addr = volo::net::Address::from(addr);
volo_gen::proto_gen::hello::HelloServiceServer::new(S)
.run(addr)
.await
.unwrap();
}
Change it to this:
use std::net::SocketAddr;
use volo_grpc::server::{Server, ServiceBuilder};
#[volo::main]
async fn main() {
let addr: SocketAddr = "[::]:8080".parse().unwrap();
let addr = volo::net::Address::from(addr);
Server::new()
.add_service(ServiceBuilder::new(volo_gen::proto_gen::hello::GreeterServer::new(S)).build())
.run(addr)
.await
.unwrap();
}
gRPC Compression
Thanks to @tuchg for bringing us gRPC compression and decompression support in #91 , if there is a requirement for the transmission size, this function can be used.
Thrift Codec refactoring
In the previous Codec design, Thrift codec was specified by CodecType
, which brought two problems:
- It is not easy to extend new protocol support, all supported protocols need to be implemented in the framework and hard-coded into CodecType;
- It is impossible to decouple and arrange the Transport and Serialize protocols. For example, if we want to support the TCompact protocol, then we need to add multiple variants: TTHeaderFramedCompact, TTheaderCompact, FramedCompact, Compact…
At the same time, the previous codec did not achieve Zero Copy, and there is room for improvement in performance.
This refactoring solves all the above problems at once. We no longer rely on CodecType
to specify the codec method, but use the make_codec
interface to specify the Codec generation method, so that we can easily Expand new protocol support, and also decouple and arrange Transport and Serialize protocols.
For details, please refer to codec documentation.
Thrift generated code default field change
In the previous generated code, the binary type will generate Vec<u8>
, and the string type will generate String, which will cause a clone to be performed when decoding and encoding, and the performance loss will be large; in this version, we will use these two The Rust type generated by default for this type has been changed to Bytes and FastStr to achieve full-link Zero Copy, because in practice we have observed absolutely Most of the binary and string in Request / Response will not be modified, and even if the user needs to modify, it is at the cost of one Clone, and the performance will not be worse than before.
This is a breaking change. Users of previous versions may need to modify the code after upgrading. Generally speaking, only need to modify the type according to the error message.
If there is still a need to generate String
for string, you can add an annotation of pilota.rust_type="string"
to the corresponding field in the thrift idl file, as follows:
struct Item {
1: required string name (pilota. rust_type="string");
}
In addition, Pilota also supports other annotations. For details, please refer to: Pilota Supported Annotations
Full Release Note
The complete Release Note can be referred to: https://github.com/cloudwego/volo/releases/tag/volo-0.3.0