2019-08-25 02:19:11 +00:00
|
|
|
use crate::request::{FromRequest, Outcome, Request};
|
2019-12-11 00:34:23 +00:00
|
|
|
use tokio::sync::mpsc;
|
2019-08-25 02:19:11 +00:00
|
|
|
|
2019-12-20 02:11:32 +00:00
|
|
|
/// A `ShutdownHandle` can be used to instruct a Rocket server to gracefully
|
|
|
|
/// shut down. Once a server shutdown has been requested manually by calling
|
|
|
|
/// [`ShutdownHandle::shutdown()`] or automatically by `Ctrl-C` being pressed
|
|
|
|
/// (if enabled), Rocket will finish handling any pending requests and return to
|
2020-02-03 08:53:59 +00:00
|
|
|
/// the caller of [`Rocket::serve()`] or [`Rocket::launch()`].
|
|
|
|
///
|
|
|
|
/// [`Rocket::serve()`]: crate::Rocket::serve()
|
|
|
|
/// [`Rocket::launch()`]: crate::Rocket::launch()
|
2019-12-20 02:11:32 +00:00
|
|
|
///
|
2019-08-25 02:19:11 +00:00
|
|
|
/// # Example
|
|
|
|
///
|
2020-06-16 12:01:26 +00:00
|
|
|
/// ```rust,no_run
|
2019-08-25 02:19:11 +00:00
|
|
|
/// # #[macro_use] extern crate rocket;
|
|
|
|
/// #
|
|
|
|
/// use rocket::shutdown::ShutdownHandle;
|
|
|
|
///
|
|
|
|
/// #[get("/shutdown")]
|
|
|
|
/// fn shutdown(handle: ShutdownHandle) -> &'static str {
|
|
|
|
/// handle.shutdown();
|
|
|
|
/// "Shutting down..."
|
|
|
|
/// }
|
|
|
|
///
|
2020-06-14 15:57:55 +00:00
|
|
|
/// #[rocket::main]
|
|
|
|
/// async fn main() {
|
2020-06-16 12:01:26 +00:00
|
|
|
/// let result = rocket::ignite()
|
2019-08-25 02:19:11 +00:00
|
|
|
/// .mount("/", routes![shutdown])
|
|
|
|
/// .launch()
|
2020-06-16 12:01:26 +00:00
|
|
|
/// .await;
|
|
|
|
///
|
|
|
|
/// // If the server shut down (by visting `/shutdown`), `result` is `Ok`.
|
|
|
|
/// result.expect("server failed unexpectedly");
|
2019-08-25 02:19:11 +00:00
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct ShutdownHandle(pub(crate) mpsc::Sender<()>);
|
|
|
|
|
|
|
|
impl ShutdownHandle {
|
2019-12-20 02:11:32 +00:00
|
|
|
/// Notify Rocket to shut down gracefully. This function returns
|
|
|
|
/// immediately; pending requests will continue to run until completion
|
|
|
|
/// before the actual shutdown occurs.
|
2019-08-25 02:19:11 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn shutdown(mut self) {
|
|
|
|
// Intentionally ignore any error, as the only scenarios this can happen
|
|
|
|
// is sending too many shutdown requests or we're already shut down.
|
|
|
|
let _ = self.0.try_send(());
|
2019-12-11 00:34:23 +00:00
|
|
|
info!("Server shutdown requested, waiting for all pending requests to finish.");
|
2019-08-25 02:19:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-31 09:34:15 +00:00
|
|
|
#[crate::async_trait]
|
|
|
|
impl<'a, 'r> FromRequest<'a, 'r> for ShutdownHandle {
|
2019-08-25 02:19:11 +00:00
|
|
|
type Error = std::convert::Infallible;
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-31 09:34:15 +00:00
|
|
|
async fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
2019-08-25 02:19:11 +00:00
|
|
|
Outcome::Success(request.state.managed.get::<ShutdownHandleManaged>().0.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Use this type in managed state to avoid placing `ShutdownHandle` in it.
|
|
|
|
pub(crate) struct ShutdownHandleManaged(pub ShutdownHandle);
|