Only extract needed values in 'async_main'.

Previously, `async_main` would extract a full `Config`. This mean that values
like `address` were read and parsed even when they were unused. Should they
exist and be malformed, a configuration error would needlessly arise.

This commit fixes this by only extract values that are subsequently used.
This commit is contained in:
Sergio Benitez 2023-05-18 17:33:57 -07:00
parent 9f65977b99
commit 29cd271f8a
3 changed files with 26 additions and 11 deletions

View File

@ -306,10 +306,7 @@ impl Config {
/// let config = Config::from(figment); /// let config = Config::from(figment);
/// ``` /// ```
pub fn from<T: Provider>(provider: T) -> Self { pub fn from<T: Provider>(provider: T) -> Self {
Self::try_from(provider).unwrap_or_else(|e| { Self::try_from(provider).unwrap_or_else(bail_with_config_error)
pretty_print_error(e);
panic!("aborting due to configuration error(s)")
})
} }
/// Returns `true` if TLS is enabled. /// Returns `true` if TLS is enabled.
@ -588,12 +585,18 @@ impl<'r> FromRequest<'r> for &'r Config {
} }
} }
#[doc(hidden)]
pub fn bail_with_config_error<T>(error: figment::Error) -> T {
pretty_print_error(error);
panic!("aborting due to configuration error(s)")
}
#[doc(hidden)] #[doc(hidden)]
pub fn pretty_print_error(error: figment::Error) { pub fn pretty_print_error(error: figment::Error) {
use figment::error::{Kind, OneOf}; use figment::error::{Kind, OneOf};
crate::log::init_default(); crate::log::init_default();
error!("Rocket configuration extraction from provider failed."); error!("Failed to extract valid configuration.");
for e in error { for e in error {
fn w<T: std::fmt::Display>(v: T) -> Paint<T> { Paint::white(v) } fn w<T: std::fmt::Display>(v: T) -> Paint<T> { Paint::white(v) }

View File

@ -123,7 +123,8 @@ mod tls;
mod secret_key; mod secret_key;
#[doc(hidden)] #[doc(hidden)]
pub use config::pretty_print_error; pub use config::{pretty_print_error, bail_with_config_error};
pub use config::Config; pub use config::Config;
pub use crate::log::LogLevel; pub use crate::log::LogLevel;
pub use shutdown::Shutdown; pub use shutdown::Shutdown;

View File

@ -261,11 +261,22 @@ pub fn async_test<R>(fut: impl std::future::Future<Output = R>) -> R {
/// WARNING: This is unstable! Do not use this method outside of Rocket! /// WARNING: This is unstable! Do not use this method outside of Rocket!
#[doc(hidden)] #[doc(hidden)]
pub fn async_main<R>(fut: impl std::future::Future<Output = R> + Send) -> R { pub fn async_main<R>(fut: impl std::future::Future<Output = R> + Send) -> R {
// FIXME: These config values won't reflect swaps of `Rocket` in attach // FIXME: We need to run `fut` to get the user's `Figment` to properly set
// fairings with different config values, or values from non-Rocket configs. // up the async env, but we need the async env to run `fut`. So we're stuck.
// See tokio-rs/tokio#3329 for a necessary solution in `tokio`. // Tokio doesn't let us take the state from one async env and migrate it to
let c = Config::from(Config::figment()); // another, so we need to use one, making this impossible.
async_run(fut, c.workers, c.max_blocking, c.shutdown.force, "rocket-worker-thread") //
// So as a result, we only use values from Rocket's figment. These
// values won't reflect swaps of `Rocket` in attach fairings with different
// config values, or values from non-Rocket configs. See tokio-rs/tokio#3329
// for a necessary resolution in `tokio`.
use config::bail_with_config_error as bail;
let fig = Config::figment();
let workers = fig.extract_inner(Config::WORKERS).unwrap_or_else(bail);
let max_blocking = fig.extract_inner(Config::MAX_BLOCKING).unwrap_or_else(bail);
let force = fig.focus(Config::SHUTDOWN).extract_inner("force").unwrap_or_else(bail);
async_run(fut, workers, max_blocking, force, "rocket-worker-thread")
} }
/// Executes a `future` to completion on a new tokio-based Rocket async runtime. /// Executes a `future` to completion on a new tokio-based Rocket async runtime.