Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion docs/quick_start.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ impl ProxyHttp for LB {

println!("upstream peer is: {upstream:?}");

// Set SNI to one.one.one.one
// `HttpPeer::new(address, tls, sni)`:
// - `true` enables TLS, because the 1.1.1.1 demo backends are served over HTTPS.
// Use `false` for a plain-HTTP upstream (e.g. a local server).
// - the SNI `one.one.one.one` must match the upstream's TLS certificate.
// When TLS is disabled the SNI is unused, so pass an empty string instead.
let peer = Box::new(HttpPeer::new(upstream, true, "one.one.one.one".to_string()));
Ok(peer)
}
Expand Down Expand Up @@ -162,6 +166,34 @@ Well done! At this point you have a functional load balancer. It is a _very_
basic load balancer though, so the next section will walk you through how to
make it more robust with some built-in pingora tooling.

### Adapt it to your needs

The example above is tuned for the 1.1.1.1 demo backends, which are served over
HTTPS. To point the load balancer at your own upstreams, two things usually need
to change:

- The backend addresses passed to `LoadBalancer::try_from_iter` in `main()`.
- How the `HttpPeer` is built in `upstream_peer()`.

For example, to balance across two local plain-HTTP servers on `127.0.0.1:9000`
and `127.0.0.1:9001`, list them as the upstreams:

```rust
let upstreams =
LoadBalancer::try_from_iter(["127.0.0.1:9000", "127.0.0.1:9001"]).unwrap();
```

Then disable TLS when constructing the peer. A plain-HTTP upstream has no
certificate, so leaving TLS enabled (as in the demo) causes the connection to
fail with a `502`. Pass `false` for the `tls` argument and an empty SNI:

```rust
let peer = Box::new(HttpPeer::new(upstream, false, String::new()));
```

Finally, the `Host` header set in `upstream_request_filter()` is specific to the
1.1.1.1 backends. Update or remove it to match what your upstream expects.

## Add functionality

Pingora provides several helpful features that can be enabled and configured
Expand Down
10 changes: 8 additions & 2 deletions pingora-core/examples/service_dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ impl DatabaseService {
}
}

// Exposes a shared handle to the connection string. Dependents such as
// ApiService receive this handle and can read it once DatabaseService
// signals ready.
fn get_connection_string(&self) -> Arc<Mutex<Option<String>>> {
self.connection_string.clone()
}
Expand All @@ -84,15 +87,16 @@ impl ServiceWithDependents for DatabaseService {
// Simulate database connection setup
sleep(Duration::from_secs(2)).await;

// Store the connection string
// Store the connection string so dependents can read it once we are ready
{
let mut conn = self.connection_string.lock().await;
*conn = Some("postgresql://localhost:5432/mydb".to_string());
}

info!("DatabaseService: Initialization complete, signaling ready");

// Signal that the service is ready
// Signal readiness only after initialization completes; dependents are
// released to start once this fires.
ready_notifier.notify_ready();

// Keep running until shutdown
Expand Down Expand Up @@ -150,6 +154,8 @@ pub struct ApiService {
}

impl ApiService {
// Dependency wiring: the database connection handle is shared in from
// DatabaseService so this service can use it once that dependency is ready.
fn new(db_connection: Arc<Mutex<Option<String>>>) -> Self {
Self { db_connection }
}
Expand Down
Loading