Expand description
A typical architecture of network service is that after receiving a request, the network tasks dispatch it to the business tasks according to some fields. In this way, requests for the same content can be dispatched in the same task to avoid shared state or locking. This tokio tutorial gives detailed description.
The same is true in tonic’s gRPC server. The dispatch of requests
from network tasks to the business task has a pattern. This crate is
an abstraction of this pattern to simplify the repetitive work in
the application.
§Usage
Let’s take the DictService as example.
We assume that you are familiar with how to implement the original tonic server. Here we just talk about the parts related to this crate.
-
Add this Crate
Add this crate and
pasteto your Cargo.toml.tonic-server-dispatch = "*" paste = "1.0" -
Define your Service
This macro builds the mapping relationship between tonic network tasks and your business tasks.
dispatch_service! { DictService, // original service name key, // hash by this request field // service methods set(SetRequest) -> SetReply, get(Key) -> Value, delete(Key) -> Value, }This macro is the main part of this crate. Go to its doc page for more detail.
-
Implement your Service
Define your business context for each task, and implement
DispatchBackendfor it.DispatchBackenddefines all service methods, similar to the original tonic ones.#[derive(Default)] struct DictCtx (HashMap<String, f64>); impl DispatchBackend for DictCtx { async fn get(&mut self, req: Key) -> Result<Value, Status> { match self.0.get(&req.key) { Some(value) => Ok(Value { value: *value }), None => Err(Status::not_found(String::new())), } } // all other methods ... }Compare to the original tonic prototype:
async fn get(&self, req: tonic::Request<Key>) -> Result<tonic::Response<Value>, tonic::Status>the difference:
&self->&mut selftonic::Request<Key>->Keytonic::Response<Value>->Value
-
Start your Service
This starts backend tasks and creates channels. The requests are dispatched from network tasks to backend tasks by the channels, and the response are sent back by oneshot channels.
let svc = start_simple_dispatch_backend::<DictCtx>(16, 10);As the function’s name suggests, it just starts the simple kind of backend task, which just listen on the request channel. If you want more complex backend task (e.g. listen on another channel too), you have to create tasks and channels youself. However, the implementation of this function can also be used as your reference.
Now we have finished the dispatch level. It is very simple, isn’t it? Go DictService for the full source code.
Macros§
- dispatch_
service - Define the service and build the mapping relationship between tonic network tasks and your business tasks.