1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
use std::future::Future; use std::task::{Context, Poll}; use std::pin::Pin; use futures::FutureExt; use crate::request::{FromRequest, Outcome, Request}; use crate::trip_wire::TripWire; /// A request guard and future for graceful shutdown. /// /// A server shutdown is manually requested by calling [`Shutdown::notify()`] /// or, if enabled, through [automatic triggers] like `Ctrl-C`. Rocket will stop accepting new /// requests, finish handling any pending requests, wait a grace period before /// cancelling any outstanding I/O, and return `Ok()` to the caller of /// [`Rocket::launch()`]. Graceful shutdown is configured via /// [`config::Shutdown`](crate::config::Shutdown). /// /// [`Rocket::launch()`]: crate::Rocket::launch() /// [automatic triggers]: crate::config::Shutdown#triggers /// /// # Detecting Shutdown /// /// `Shutdown` is also a future that resolves when [`Shutdown::notify()`] is /// called. This can be used to detect shutdown in any part of the application: /// /// ```rust /// # use rocket::*; /// use rocket::Shutdown; /// /// #[get("/wait/for/shutdown")] /// async fn wait_for_shutdown(shutdown: Shutdown) -> &'static str { /// shutdown.await; /// "Somewhere, shutdown was requested." /// } /// ``` /// /// See the [`stream`](crate::response::stream#graceful-shutdown) docs for an /// example of detecting shutdown in an infinite responder. /// /// Additionally, a completed shutdown request resolves the future returned from /// [`Rocket::launch()`](crate::Rocket::launch()): /// /// ```rust,no_run /// # #[macro_use] extern crate rocket; /// # /// use rocket::Shutdown; /// /// #[get("/shutdown")] /// fn shutdown(shutdown: Shutdown) -> &'static str { /// shutdown.notify(); /// "Shutting down..." /// } /// /// #[rocket::main] /// async fn main() { /// let result = rocket::build() /// .mount("/", routes![shutdown]) /// .launch() /// .await; /// /// // If the server shut down (by visiting `/shutdown`), `result` is `Ok`. /// result.expect("server failed unexpectedly"); /// } /// ``` #[derive(Debug, Clone)] #[must_use = "`Shutdown` does nothing unless polled or `notify`ed"] pub struct Shutdown(pub(crate) TripWire); impl Shutdown { /// Notify the application to shut down gracefully. /// /// This function returns immediately; pending requests will continue to run /// until completion or expiration of the grace period, which ever comes /// first, before the actual shutdown occurs. The grace period can be /// configured via [`Shutdown::grace`](crate::config::Shutdown::grace). /// /// ```rust /// # use rocket::*; /// use rocket::Shutdown; /// /// #[get("/shutdown")] /// fn shutdown(shutdown: Shutdown) -> &'static str { /// shutdown.notify(); /// "Shutting down..." /// } /// ``` #[inline] pub fn notify(self) { self.0.trip(); } } #[crate::async_trait] impl<'r> FromRequest<'r> for Shutdown { type Error = std::convert::Infallible; #[inline] async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> { Outcome::Success(request.rocket().shutdown()) } } impl Future for Shutdown { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { self.0.poll_unpin(cx) } } #[cfg(test)] mod tests { use super::Shutdown; #[test] fn ensure_is_send_sync_clone_unpin() { fn is_send_sync_clone_unpin<T: Send + Sync + Clone + Unpin>() {} is_send_sync_clone_unpin::<Shutdown>(); } }