comprehensive 0.2.0

A harness for creating consistently-shaped servers will less boilerplate
Documentation

A harness for creating consistently-shaped servers will less boilerplate.

Production-ready servers require a comprehensive collection of basic features to enable easy deployment, integration, diagnostics, monitoring, lifecycle management, and so forth. Individual features may be available in the ecosystem, but each requires its own boilerplate to add and configure. Especially when operating with a microservices paradigm, the effort to bootstrap a basic batteries-included server may even outweigh the application logic.

Comprehensive's goal is that it should be easy to create a server with a number of important basic features included by default, including:

  • Secure servers available by default for both gRPC (mTLS) and HTTP
  • easy to provision with keys and certificates using infrastructure like cert-manager in Kubernetes.
  • dynamically reloaded so that certificate renewals happen
  • Health checking endpoints for servers enabled by default.
  • Metrics (which can be scraped by Prometheus) exported.
  • Common metrics like RPC counters automatically installed.
  • Graceful shutdown
  • Server reflection, ACLs, and more.

This framework is opinionated, not because its decisions are considered better than alternatives but because it's important for consistency. Deployment, configuration, diagnostics, metrics collection and more should happen in the same way across a whole zoo of different servers in a cluster (or other collective environment).

Status

Comprehensive is still in early development. Many more features are planned.

Hello world server

// Generated protobufs for gRPC
# #[cfg(feature = "grpc")]
mod pb {
tonic::include_proto!("comprehensive");
pub const FILE_DESCRIPTOR_SET: &[u8] =
tonic::include_file_descriptor_set!("fdset");
}
# #[cfg(feature = "grpc")]
use pb::*;

#[derive(clap::Args, Debug)]
struct Args {
#[arg(long)]
app_flag: Option<String>,
}

#[derive(comprehensive::ResourceDependencies)]
struct ApplicationDependencies {
// Temporary resource type while migrating!
monolith: std::sync::Arc<comprehensive::DeprecatedMonolith>,
}

struct ApplicationWorkResource;

impl comprehensive::Resource for ApplicationWorkResource {
type Args = Args;
type Dependencies = ApplicationDependencies;
const NAME: &str = "application";

fn new(d: ApplicationDependencies, args: Args) -> Result<Self, Box<dyn std::error::Error>> {
# #[cfg(feature = "grpc")]
let srv = TestServer{};
# #[cfg(feature = "grpc")]
d.monolith.configure(|b| Ok(b
.register_encoded_file_descriptor_set(pb::FILE_DESCRIPTOR_SET)
.add_grpc_service(pb::test_server::TestServer::new(srv))?
))?;
Ok(Self)
}
}

#[derive(comprehensive::ResourceDependencies)]
struct TopDependencies(std::sync::Arc<ApplicationWorkResource>);
# struct TestServer {}
# #[cfg(feature = "grpc")]
# #[tonic::async_trait]
# impl pb::test_server::Test for TestServer {
#     async fn greet(&self, _: tonic::Request<()>) -> Result<tonic::Response<pb::GreetResponse>, tonic::Status> {
#         Ok(tonic::Response::new(pb::GreetResponse::default()))
#     }
# }

#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Required if TLS is needed.
# #[cfg(feature = "tls")]
let _ = tokio_rustls::rustls::crypto::aws_lc_rs::default_provider().install_default();

// Will start a gRPC server with or without TLS depending on flags,
// with extra features such as server reflection, and also serve
// HTTP and/or HTTPS (again, depending on flags) at least for metrics.
comprehensive::Assembly::<TopDependencies>::new()?.run().await?;
Ok(())
}

Feature Flags

  • grpc: Enables the gRPC server. Requires tonic.
  • tls: Enables secure versions of each protocol (currently gRPC and HTTP). Requires rustls.

Most features, such as HTTP and Prometheus metrics, are always available.