Ce contenu n’est pas encore disponible dans votre langue.
This article describes how the Rust apps in your Aspire solution connect to other resources, in both directions. When another resource references a Rust app, Aspire injects the Rust app’s URL into that resource, so apps written in C#, Go, Python, TypeScript, or Rust can call it without hard-coded addresses. When a Rust app references other resources — such as a database, a cache, or another service — Aspire injects their URLs and connection details into the app’s environment, where your code reads them with std::env::var. It also describes how Rust apps send telemetry to the Aspire dashboard and trust the development certificate.
The examples in this article use the following AppHost. The orders Rust app references a PostgreSQL database and the catalog Rust app, and a Node.js storefront app references orders:
WithReferencewithReference injects the referenced resource’s connection information into the referencing resource, and WaitForwaitFor delays the referencing resource until the referenced one is running — or healthy, when it has a health check. A Rust app can be on either side of a reference, and the environment variables are the same whatever language the other app uses.
AddRustAppaddRustApp doesn’t add an endpoint, so each Rust app in the preceding AppHost gets one from WithHttpEndpointwithHttpEndpoint, which passes the app its port in the PORT environment variable. Each app also gets a health check from WithHttpHealthCheckwithHttpHealthCheck. Without it, orders would start as soon as Cargo starts building catalog, rather than when catalog is ready for requests.
Aspire passes connection information to apps as environment variables. A Rust app is on both sides of that exchange: it exposes endpoints that other apps call, and it receives variables of its own.
When a resource references a Rust app, Aspire injects the URL of each of the Rust app’s endpoints. In the preceding AppHost, storefront receives the following variables for the orders app:
Environment variable
Description
ORDERS_HTTP
The URL of the orders app’s http endpoint, named {RESOURCE}_{ENDPOINT}. Read this variable from apps that don’t use .NET service discovery.
WithHttpEndpoint names its endpoint http unless you pass a name. When you add an endpoint with a different name to a Rust app, the variables use that name instead — for example, an endpoint named admin produces ORDERS_ADMIN. For the naming rules, see Endpoint URLs and Service discovery variables.
A Rust app receives the variables of every resource that it references. In the preceding AppHost, orders receives CATALOG_HTTP and services__catalog__http__0 for the catalog app, and the connection properties of the ordersdb database, which include:
Environment variable
Description
ORDERSDB_URI
The connection URI, in the format postgresql://{Username}:{Password}@{Host}:{Port}/{DatabaseName}. Rust database crates such as sqlx accept it as-is.
Apps call a Rust app at the URL that Aspire injects. Each example calls the orders app from the storefront app in the preceding AppHost. Only the language differs.
The https+http scheme prefers an HTTPS endpoint and falls back to HTTP. Without service discovery, read the URL from the ORDERS_HTTP configuration value instead.
There’s no Aspire client crate for Rust. A Rust app reads the variables that Aspire injects with std::env::var, and passes them to the crates that it already uses. The following example configures the orders app from the preceding AppHost to listen on its port, call the catalog app, and use the ordersdb database. It uses axum for the web server, reqwest for the HTTP client, and sqlx for the database. Add them to the app:
Terminal
cargoaddaxumreqwest
cargoaddtokio--featuresmacros,rt-multi-thread
cargoaddsqlx--featurespostgres,runtime-tokio
Then read the variables when the app starts:
src/main.rs
use std::{env, net::SocketAddr};
use axum::{extract::State, http::StatusCode, routing::get,Router};
The defaults for CATALOG_HTTP and PORT keep the app runnable outside Aspire, alongside a catalog app that listens on port 8080. Reading ORDERSDB_URI with the ? operator makes the app exit with an error when the variable isn’t set.
Every Rust resource receives the standard OpenTelemetry environment variables, but a Rust app doesn’t export telemetry by itself, and Rust has no automatic instrumentation agent. To send telemetry to the dashboard, configure the OpenTelemetry SDK for Rust with the OTLP exporter from the opentelemetry-otlp crate. The exporter reads the dashboard’s endpoint and the headers that authenticate with it from the OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS variables, and the SDK reads the app’s name from OTEL_SERVICE_NAME. Configure the exporter as follows:
Use the gRPC transport. Aspire points OTEL_EXPORTER_OTLP_ENDPOINT at the dashboard’s gRPC endpoint whenever the dashboard has one, and sets OTEL_EXPORTER_OTLP_PROTOCOL to grpc. Select the gRPC transport explicitly with with_tonic(), because only the gRPC exporter builder accepts the TLS configuration that the next item describes. If the dashboard has only an OTLP/HTTP endpoint, Aspire sets OTEL_EXPORTER_OTLP_PROTOCOL to http/protobuf instead. In that case, build the exporter with with_http(), and configure certificate trust on the HTTP client that it uses. For the dashboard’s endpoint settings, see Dashboard configuration.
Trust the native certificate roots. When you run the AppHost, the dashboard’s endpoint typically uses HTTPS with the development certificate. Configure the exporter’s TLS with ClientTlsConfig::new().with_native_roots(), which loads certificates from the SSL_CERT_DIR directory that Aspire sets.
Select one TLS provider for both crates. Enable the same rustls crypto provider — tls-aws-lc or tls-ring — on opentelemetry-otlp and on tonic. Cargo features are additive, so selecting different providers compiles both of them, rather than replacing one with the other.
The following dependencies export traces over gRPC with AWS-LC as the TLS provider, as the Aspire Rust playground does. Building AWS-LC requires native build tools, such as a C compiler. To use ring instead, replace tls-aws-lc with tls-ring for both crates. Keep the tonic version in step with the one that opentelemetry-otlp uses, because the exporter’s with_tls_config method takes tonic’s ClientTlsConfig type.
The dashboard shows the spans under the app’s resource name, which Aspire passes to the SDK in OTEL_SERVICE_NAME. To export metrics and logs as well, and to connect the spans and events of the tracing crate to OpenTelemetry, see the telemetry.rs file of the Aspire Rust playground. An app that doesn’t configure the SDK doesn’t send telemetry to the dashboard, but its console output still appears in the dashboard’s console logs.
When you run the AppHost, Aspire sets SSL_CERT_DIR on each Rust app to a directory that contains the development certificate. OpenSSL, and clients that load their trusted certificates with the rustls-native-certs crate — such as tonic with with_native_roots() — read that variable, so they trust HTTPS endpoints that use the development certificate without any code changes. On Windows and macOS, those clients then typically trust only the development certificate, rather than public certificate authorities, unless you set the app’s trust scope to System. Clients that use the operating system’s certificate store, and clients that use the built-in certificates of the webpki-roots crate, behave differently. For details, see Configure certificate trust.