From 46c441ad8be35074ac786a8d285a61f4496ce191 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Sat, 7 May 2022 15:54:21 -0500 Subject: [PATCH] Add 'rocket::execute()'. The function allows executing arbitrary futures, including Rocket's `launch()` future, on Rocket's async runtime. Resolves #1881. --- core/lib/src/lib.rs | 81 ++++++++++++++++++++++++++++++++++++++++++ core/lib/src/rocket.rs | 4 +++ 2 files changed, 85 insertions(+) diff --git a/core/lib/src/lib.rs b/core/lib/src/lib.rs index 1d0c43e9..edfb0504 100644 --- a/core/lib/src/lib.rs +++ b/core/lib/src/lib.rs @@ -266,3 +266,84 @@ pub fn async_main(fut: impl std::future::Future + Send) -> R { let config = Config::from(Config::figment()); async_run(fut, config.workers, config.shutdown.force, "rocket-worker-thread") } + +/// Executes a `future` to completion on a new tokio-based Rocket async runtime. +/// +/// The runtime is terminated on shutdown, and the future's resolved value is +/// returned. +/// +/// # Considerations +/// +/// This function is a low-level mechanism intended to be used to execute the +/// future returned by [`Rocket::launch()`] in a self-contained async runtime +/// designed for Rocket. It runs futures in exactly the same manner as +/// [`#[launch]`](crate::launch) and [`#[main]`](crate::main) do and is thus +/// _never_ the preferred mechanism for running a Rocket application. _Always_ +/// prefer to use the [`#[launch]`](crate::launch) or [`#[main]`](crate::main) +/// attributes. For example [`#[main]`](crate::main) can be used even when +/// Rocket is just a small part of a bigger application: +/// +/// ```rust,no_run +/// #[rocket::main] +/// async fn main() { +/// # let should_start_server_in_foreground = false; +/// # let should_start_server_in_background = false; +/// let rocket = rocket::build(); +/// if should_start_server_in_foreground { +/// rocket::build().launch().await; +/// } else if should_start_server_in_background { +/// rocket::tokio::spawn(rocket.launch()); +/// } else { +/// // do something else +/// } +/// } +/// ``` +/// +/// See [Rocket#launching] for more on using these attributes. +/// +/// # Example +/// +/// Build an instance of Rocket, launch it, and wait for shutdown: +/// +/// ```rust,no_run +/// use rocket::fairing::AdHoc; +/// +/// let rocket = rocket::build() +/// .attach(AdHoc::on_liftoff("Liftoff Printer", |_| Box::pin(async move { +/// println!("Stalling liftoff for a second..."); +/// rocket::tokio::time::sleep(std::time::Duration::from_secs(1)).await; +/// println!("And we're off!"); +/// }))); +/// +/// rocket::execute(rocket.launch()); +/// ``` +/// +/// Launch a pre-built instance of Rocket and wait for it to shutdown: +/// +/// ```rust,no_run +/// use rocket::{Rocket, Ignite, Phase, Error}; +/// +/// fn launch(rocket: Rocket

) -> Result, Error> { +/// rocket::execute(rocket.launch()) +/// } +/// ``` +/// +/// Do async work to build an instance of Rocket, launch, and wait for shutdown: +/// +/// ```rust,no_run +/// use rocket::fairing::AdHoc; +/// +/// // This line can also be inside of the `async` block. +/// let rocket = rocket::build(); +/// +/// rocket::execute(async move { +/// let rocket = rocket.ignite().await?; +/// let config = rocket.config(); +/// rocket.launch().await +/// }); +/// ``` +pub fn execute(future: F) -> R + where F: std::future::Future + Send +{ + async_main(future) +} diff --git a/core/lib/src/rocket.rs b/core/lib/src/rocket.rs index 8acf8312..338c8a7b 100644 --- a/core/lib/src/rocket.rs +++ b/core/lib/src/rocket.rs @@ -99,6 +99,10 @@ use crate::log::PaintExt; /// } /// ``` /// +/// For extreme and rare cases in which [`#[main]`](crate::main) imposes +/// obstinate restrictions, use [`rocket::execute()`](crate::execute()) to +/// execute Rocket's `launch()` future. +/// /// * **Automatic Launching** /// /// Manually progressing an instance of Rocket though its phases is only