From 02680076eb0b49965063e35a801d5882e367368a Mon Sep 17 00:00:00 2001 From: Matthew Pomes Date: Sun, 7 Jul 2024 17:35:11 -0500 Subject: [PATCH 1/6] Drop Rocket inside the tokio async context when using launch Moves error printing and the implicit drop inside the tokio runtime when using the `#[launch]` attribute. --- core/codegen/src/attribute/entry/launch.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/codegen/src/attribute/entry/launch.rs b/core/codegen/src/attribute/entry/launch.rs index a97c5eaa5d..48dcda3d14 100644 --- a/core/codegen/src/attribute/entry/launch.rs +++ b/core/codegen/src/attribute/entry/launch.rs @@ -113,7 +113,9 @@ impl EntryAttr for Launch { #[allow(dead_code)] #f #vis #sig { - #_error::Error::report(::rocket::async_main(#launch)) + ::rocket::async_main(async move { + #_error::Error::report(#launch.await) + }) } )) } From 24a84d52e496a703d280699e4418575f0b5b0e80 Mon Sep 17 00:00:00 2001 From: Matthew Pomes Date: Fri, 9 Aug 2024 23:01:18 -0500 Subject: [PATCH 2/6] Add test to validate new behavior --- core/lib/tests/drop-in-async-context.rs | 50 +++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 core/lib/tests/drop-in-async-context.rs diff --git a/core/lib/tests/drop-in-async-context.rs b/core/lib/tests/drop-in-async-context.rs new file mode 100644 index 0000000000..099a6d6f5c --- /dev/null +++ b/core/lib/tests/drop-in-async-context.rs @@ -0,0 +1,50 @@ +#[macro_use] extern crate rocket; + +use rocket::{Rocket, Build, build, fairing::AdHoc, Orbit}; + +struct AsyncDropInAsync; + +impl Drop for AsyncDropInAsync { + fn drop(&mut self) { + // Attempt to fetch the current runtime while dropping + // Pools in rocket_sync_db_pools (and maybe rocket_db_pools) + // do use this capability. They spawn tasks to asyncronously + // complete shutdown of the pool, which triggers the same panic. + let _ = rocket::tokio::runtime::Handle::current(); + } +} + +fn rocket() -> Rocket { + build().manage(AsyncDropInAsync).attach(AdHoc::on_liftoff( + "Shutdown immediately", + |rocket: &Rocket| Box::pin(async { + rocket.shutdown().notify(); + } + ))) +} + +mod launch { + #[launch] + fn launch() -> _ { + super::rocket() + } + #[test] + fn test_launch() { + main(); + } +} + +mod main { + #[rocket::main] + async fn main() { + super::rocket().launch().await.unwrap(); + } + #[test] + fn test_main() { + main(); + } + #[test] + fn test_execute() { + rocket::execute(super::rocket().launch()).unwrap(); + } +} From 82430041b3cbae3cde2c2dbba5eddfa55c8adbfc Mon Sep 17 00:00:00 2001 From: Matthew Pomes Date: Fri, 9 Aug 2024 23:37:57 -0500 Subject: [PATCH 3/6] Update tests to prevent collisions --- core/lib/tests/drop-in-async-context.rs | 29 ++++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/core/lib/tests/drop-in-async-context.rs b/core/lib/tests/drop-in-async-context.rs index 099a6d6f5c..cfe8a318e1 100644 --- a/core/lib/tests/drop-in-async-context.rs +++ b/core/lib/tests/drop-in-async-context.rs @@ -1,6 +1,7 @@ -#[macro_use] extern crate rocket; +#[macro_use] +extern crate rocket; -use rocket::{Rocket, Build, build, fairing::AdHoc, Orbit}; +use rocket::{build, fairing::AdHoc, Build, Orbit, Rocket}; struct AsyncDropInAsync; @@ -17,10 +18,12 @@ impl Drop for AsyncDropInAsync { fn rocket() -> Rocket { build().manage(AsyncDropInAsync).attach(AdHoc::on_liftoff( "Shutdown immediately", - |rocket: &Rocket| Box::pin(async { - rocket.shutdown().notify(); - } - ))) + |rocket: &Rocket| { + Box::pin(async { + rocket.shutdown().notify(); + }) + }, + )) } mod launch { @@ -35,9 +38,14 @@ mod launch { } mod main { + use rocket::tokio::net::TcpListener; + #[rocket::main] async fn main() { - super::rocket().launch().await.unwrap(); + super::rocket() + .try_launch_on(TcpListener::bind("localhost:8001")) + .await + .unwrap(); } #[test] fn test_main() { @@ -45,6 +53,11 @@ mod main { } #[test] fn test_execute() { - rocket::execute(super::rocket().launch()).unwrap(); + rocket::execute(async { + super::rocket() + .try_launch_on(TcpListener::bind("localhost:8002")) + .await + .unwrap(); + }); } } From f803288f7515acf407899c64dc437591c60ea7b1 Mon Sep 17 00:00:00 2001 From: Matthew Pomes Date: Sat, 10 Aug 2024 00:36:13 -0500 Subject: [PATCH 4/6] Update tests to set secret key so they work on release --- core/lib/tests/drop-in-async-context.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/lib/tests/drop-in-async-context.rs b/core/lib/tests/drop-in-async-context.rs index cfe8a318e1..80ee09d5e7 100644 --- a/core/lib/tests/drop-in-async-context.rs +++ b/core/lib/tests/drop-in-async-context.rs @@ -1,7 +1,8 @@ #[macro_use] extern crate rocket; -use rocket::{build, fairing::AdHoc, Build, Orbit, Rocket}; +use figment::Figment; +use rocket::{custom, fairing::AdHoc, Build, Orbit, Rocket, config::SecretKey}; struct AsyncDropInAsync; @@ -16,7 +17,10 @@ impl Drop for AsyncDropInAsync { } fn rocket() -> Rocket { - build().manage(AsyncDropInAsync).attach(AdHoc::on_liftoff( + let mut config = rocket::Config::default(); + config.secret_key = SecretKey::generate().unwrap(); + let figment = Figment::from(config); + custom(figment).manage(AsyncDropInAsync).attach(AdHoc::on_liftoff( "Shutdown immediately", |rocket: &Rocket| { Box::pin(async { From 81293224b8488b68960bc57ad306bd1e314b4fc3 Mon Sep 17 00:00:00 2001 From: Matthew Pomes Date: Sat, 10 Aug 2024 12:18:33 -0500 Subject: [PATCH 5/6] Update tests to use unnumbered ports --- core/lib/tests/drop-in-async-context.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/core/lib/tests/drop-in-async-context.rs b/core/lib/tests/drop-in-async-context.rs index 80ee09d5e7..e1dda6a026 100644 --- a/core/lib/tests/drop-in-async-context.rs +++ b/core/lib/tests/drop-in-async-context.rs @@ -1,8 +1,8 @@ #[macro_use] extern crate rocket; -use figment::Figment; -use rocket::{custom, fairing::AdHoc, Build, Orbit, Rocket, config::SecretKey}; +use rocket::figment::{providers::{Format as _, Toml}, Figment}; +use rocket::{custom, fairing::AdHoc, Build, Orbit, Rocket}; struct AsyncDropInAsync; @@ -18,8 +18,13 @@ impl Drop for AsyncDropInAsync { fn rocket() -> Rocket { let mut config = rocket::Config::default(); - config.secret_key = SecretKey::generate().unwrap(); - let figment = Figment::from(config); + #[cfg(feature = "secrets")] + { config.secret_key = rocket::config::SecretKey::generate().unwrap(); } + let figment = Figment::from(config).merge(Toml::string(r#" +[default] +address = "tcp:127.0.0.1:0" +port = 0 +"#).nested()); custom(figment).manage(AsyncDropInAsync).attach(AdHoc::on_liftoff( "Shutdown immediately", |rocket: &Rocket| { @@ -42,12 +47,10 @@ mod launch { } mod main { - use rocket::tokio::net::TcpListener; - #[rocket::main] async fn main() { super::rocket() - .try_launch_on(TcpListener::bind("localhost:8001")) + .launch() .await .unwrap(); } @@ -59,7 +62,7 @@ mod main { fn test_execute() { rocket::execute(async { super::rocket() - .try_launch_on(TcpListener::bind("localhost:8002")) + .launch() .await .unwrap(); }); From bd3715cbd66b2b782a42741782c7ae2a774ce472 Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Sat, 17 Aug 2024 18:43:10 -0700 Subject: [PATCH 6/6] cleanup and add new test --- core/lib/tests/drop-in-async-context.rs | 57 ++++++++++++------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/core/lib/tests/drop-in-async-context.rs b/core/lib/tests/drop-in-async-context.rs index e1dda6a026..d774f5e308 100644 --- a/core/lib/tests/drop-in-async-context.rs +++ b/core/lib/tests/drop-in-async-context.rs @@ -1,38 +1,33 @@ #[macro_use] extern crate rocket; -use rocket::figment::{providers::{Format as _, Toml}, Figment}; -use rocket::{custom, fairing::AdHoc, Build, Orbit, Rocket}; +use rocket::{Build, Config, Rocket}; +use rocket::fairing::AdHoc; +use rocket::figment::Figment; struct AsyncDropInAsync; impl Drop for AsyncDropInAsync { fn drop(&mut self) { - // Attempt to fetch the current runtime while dropping - // Pools in rocket_sync_db_pools (and maybe rocket_db_pools) - // do use this capability. They spawn tasks to asyncronously - // complete shutdown of the pool, which triggers the same panic. + // Ensure that managed state is dropped inside of an async context by + // ensuring that we do not panic when fetching the current runtime. + // + // Crates like rocket_sync_db_pools spawn tasks to asynchronously + // complete pool shutdown which must be done in an async context or else + // the spawn will panic. We want to ensure that does not happen. let _ = rocket::tokio::runtime::Handle::current(); } } fn rocket() -> Rocket { - let mut config = rocket::Config::default(); - #[cfg(feature = "secrets")] - { config.secret_key = rocket::config::SecretKey::generate().unwrap(); } - let figment = Figment::from(config).merge(Toml::string(r#" -[default] -address = "tcp:127.0.0.1:0" -port = 0 -"#).nested()); - custom(figment).manage(AsyncDropInAsync).attach(AdHoc::on_liftoff( - "Shutdown immediately", - |rocket: &Rocket| { - Box::pin(async { - rocket.shutdown().notify(); - }) - }, - )) + let figment = Figment::from(Config::debug_default()) + .merge(("address", "tcp:127.0.0.1:0")); + + rocket::custom(figment) + .manage(AsyncDropInAsync) + .attach(AdHoc::on_liftoff("Shutdown", |rocket| Box::pin(async { + rocket.shutdown().notify(); + }))) } mod launch { @@ -40,6 +35,7 @@ mod launch { fn launch() -> _ { super::rocket() } + #[test] fn test_launch() { main(); @@ -49,22 +45,23 @@ mod launch { mod main { #[rocket::main] async fn main() { - super::rocket() - .launch() - .await - .unwrap(); + super::rocket().launch().await.unwrap(); } + #[test] fn test_main() { main(); } + #[test] fn test_execute() { rocket::execute(async { - super::rocket() - .launch() - .await - .unwrap(); + super::rocket().launch().await.unwrap(); }); } + + #[test] + fn test_execute_directly() { + rocket::execute(super::rocket().launch()).unwrap(); + } }