ginepro 0.1.1

A client-side gRPC channel implementation for tonic
Documentation

ginepro offers an enriched tonic Channel using a pluggable service discovery to periodcally update the active set of gRPC servers.

Simple example

#[tokio::main]
async fn main() {
use ginepro::{LoadBalancedChannel, LoadBalancedChannelBuilder};
use shared_proto::pb::tester_client::TesterClient;

// Create a load balanced channel with the default lookup implementation.
let load_balanced_channel = LoadBalancedChannelBuilder::new_with_service(("my_hostname", 5000))
.await
.expect("failed to read system conf")
.channel();

let tester_client: TesterClient<LoadBalancedChannel> = TesterClient::new(load_balanced_channel);
}

[LoadBalancedChannel] also allows plugging in a different implementation of [LookupService].

use ginepro::{LookupService, ServiceDefinition};
use std::collections::HashSet;
use std::net::SocketAddr;

// This does nothing
struct DummyLookupService;

#[async_trait::async_trait]
impl LookupService for DummyLookupService {
async fn resolve_service_endpoints(
&self,
_definition: &ServiceDefinition,
) -> Result<HashSet<SocketAddr>, anyhow::Error> {
Ok(HashSet::new())
}
}

#[tokio::main]
async fn main() {
use ginepro::{LoadBalancedChannel, LoadBalancedChannelBuilder};
use shared_proto::pb::tester_client::TesterClient;

let load_balanced_channel = LoadBalancedChannelBuilder::new_with_service(("my_hostname", 5000))
.await
.expect("failed to read system conf")
.lookup_service(DummyLookupService)
.channel();

let tester_client: TesterClient<LoadBalancedChannel> = TesterClient::new(load_balanced_channel);
}

For systems with lower churn, the probe interval can be lowered.

#[tokio::main]
async fn main() {
use ginepro::{LoadBalancedChannel, LoadBalancedChannelBuilder};
use shared_proto::pb::tester_client::TesterClient;

let load_balanced_channel = LoadBalancedChannelBuilder::new_with_service(("my_hostname", 5000))
.await
.expect("failed to read system conf")
.dns_probe_interval(std::time::Duration::from_secs(3))
.channel();

let tester_client: TesterClient<LoadBalancedChannel> = TesterClient::new(load_balanced_channel);
}

It's also possible to associate a timeout for every new endpoint that the [LoadBalancedChannel] tries to connect to. .

#[tokio::main]
async fn main() {
use ginepro::{LoadBalancedChannel, LoadBalancedChannelBuilder};
use shared_proto::pb::tester_client::TesterClient;

let load_balanced_channel = LoadBalancedChannelBuilder::new_with_service(("my_hostname", 5000))
.await
.expect("failed to read system conf")
.timeout(std::time::Duration::from_secs(10))
.channel();

let tester_client: TesterClient<LoadBalancedChannel> = TesterClient::new(load_balanced_channel);
}

Internals

The tonic Channel exposes the function balance_channel which returnes a bounded channel through which endpoint changes can be sent. ginepro uses this message passing mechanism to report when servers are added and removed.