diff --git a/docs/quick_start.md b/docs/quick_start.md index 329a5be4..c365d06a 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -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) } @@ -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 diff --git a/pingora-core/examples/service_dependencies.rs b/pingora-core/examples/service_dependencies.rs index d5f5e392..e04331f8 100644 --- a/pingora-core/examples/service_dependencies.rs +++ b/pingora-core/examples/service_dependencies.rs @@ -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>> { self.connection_string.clone() } @@ -84,7 +87,7 @@ 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()); @@ -92,7 +95,8 @@ impl ServiceWithDependents for DatabaseService { 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 @@ -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>>) -> Self { Self { db_connection } }