Add 'rocket::execute()'.

The function allows executing arbitrary futures, including Rocket's
`launch()` future, on Rocket's async runtime.

Resolves #1881.
This commit is contained in:
Sergio Benitez 2022-05-07 15:54:21 -05:00
parent 7908dc43ca
commit 46c441ad8b
2 changed files with 85 additions and 0 deletions

View File

@ -266,3 +266,84 @@ pub fn async_main<R>(fut: impl std::future::Future<Output = R> + 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<P: Phase>(rocket: Rocket<P>) -> Result<Rocket<Ignite>, 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<R, F>(future: F) -> R
where F: std::future::Future<Output = R> + Send
{
async_main(future)
}

View File

@ -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