1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! `ginepro` offers an enriched tonic [`Channel`](tonic::transport::Channel) using a pluggable service discovery
//! to periodcally update the active set of `gRPC` servers.
//!
//! # Simple example
//!
//! ```rust
//! #[tokio::main]
//! async fn main() {
//!     use ginepro::LoadBalancedChannel;
//!     use shared_proto::pb::tester_client::TesterClient;
//!     use std::convert::TryInto;
//!
//!     // Create a load balanced channel with the default lookup implementation.
//!     let load_balanced_channel = LoadBalancedChannel::builder(("my.hostname", 5000))
//!         .channel()
//!         .await
//!         .expect("failed to construct LoadBalancedChannel");
//!
//!     let tester_client = TesterClient::new(load_balanced_channel);
//! }
//! ```
//!
//! [`LoadBalancedChannel`] also allows plugging in a different implementation of [`LookupService`].
//!
//! ```rust
//! 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;
//!     use shared_proto::pb::tester_client::TesterClient;
//!     use std::convert::TryInto;
//!
//!     // Create a load balanced channel with the default lookup implementation.
//!     let load_balanced_channel = LoadBalancedChannel::builder(("my.hostname", 5000))
//!         .lookup_service(DummyLookupService)
//!         .channel()
//!         .await
//!         .expect("failed to construct LoadBalancedChannel");
//!
//!     let tester_client = TesterClient::new(load_balanced_channel);
//! }
//! ```
//! For systems with lower churn, the probe interval can be lowered.
//!
//! ```rust
//! #[tokio::main]
//! async fn main() {
//!     use ginepro::{LoadBalancedChannel, LoadBalancedChannelBuilder};
//!     use shared_proto::pb::tester_client::TesterClient;
//!     use std::convert::TryInto;
//!
//!     let load_balanced_channel = LoadBalancedChannelBuilder::new_with_service(("my.hostname", 5000))
//!         .dns_probe_interval(std::time::Duration::from_secs(3))
//!         .channel()
//!         .await
//!         .expect("failed to construct LoadBalancedChannel");
//!
//!     let tester_client = TesterClient::new(load_balanced_channel);
//! }
//! ```
//!
//! It's also possible to associate a timeout for every new endpoint that the
//! [`LoadBalancedChannel`] tries to connect to.
//! .
//!
//! ```rust
//! #[tokio::main]
//! async fn main() {
//!     use ginepro::LoadBalancedChannel;
//!     use shared_proto::pb::tester_client::TesterClient;
//!     use std::convert::TryInto;
//!
//!     let load_balanced_channel = LoadBalancedChannel::builder(("my.hostname", 5000))
//!         .timeout(std::time::Duration::from_secs(10))
//!         .channel()
//!         .await
//!         .expect("failed to construct LoadBalancedChannel");
//!
//!     let tester_client = TesterClient::new(load_balanced_channel);
//! }
//! ```
//!
//! It's also possible to eagerly resolve the service endpoints once before
//! [`LoadBalancedChannel`] is constructed.
//! .
//!
//! ```rust,no_run
//! #[tokio::main]
//! async fn main() {
//!     use ginepro::{LoadBalancedChannel, ResolutionStrategy};
//!     use shared_proto::pb::tester_client::TesterClient;
//!     use std::time::Duration;
//!     use std::convert::TryInto;
//!
//!     let load_balanced_channel = LoadBalancedChannel::builder(("my.hostname", 5000))
//!         .timeout(std::time::Duration::from_secs(10))
//!          .resolution_strategy(ginepro::ResolutionStrategy::Eager {
//!              timeout: Duration::from_secs(20),
//!          })
//!         .channel()
//!         .await
//!         .expect("failed to construct LoadBalancedChannel");
//!
//!     let tester_client = TesterClient::new(load_balanced_channel);
//! }
//! ```
//!
//! # Internals
//! The tonic [`Channel`](tonic::transport::Channel) exposes the function
//! [`balance_channel`](tonic::transport::Channel::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.

mod balanced_channel;
mod dns_resolver;
mod lookup_service;
mod service_definition;
mod service_probe;

pub use balanced_channel::*;
pub use dns_resolver::*;
pub use lookup_service::*;
pub use service_definition::*;