Allow rest api to shutdown (#3614)

Co-authored-by: Quentin Le Sceller <q.lesceller@gmail.com>
This commit is contained in:
Ivan Sorokin 2021-03-25 14:29:24 -04:00 committed by GitHub
parent e8b46f1409
commit 4a09fed36c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 14 deletions

View file

@ -30,6 +30,7 @@ use rustls::internal::pemfile;
use std::convert::Infallible; use std::convert::Infallible;
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::fs::File; use std::fs::File;
use std::mem;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::sync::Arc; use std::sync::Arc;
use std::{io, thread}; use std::{io, thread};
@ -199,25 +200,26 @@ impl ApiServer {
addr: SocketAddr, addr: SocketAddr,
router: Router, router: Router,
) -> Result<thread::JoinHandle<()>, Error> { ) -> Result<thread::JoinHandle<()>, Error> {
if self.shutdown_sender.is_some() { if self.is_running() {
return Err(ErrorKind::Internal( return Err(ErrorKind::Internal(
"Can't start HTTP API server, it's running already".to_string(), "Can't start HTTP API server, it's running already".to_string(),
) )
.into()); .into());
} }
let (tx, _rx) = oneshot::channel::<()>(); let (tx, rx) = oneshot::channel::<()>();
self.shutdown_sender = Some(tx); self.shutdown_sender = Some(tx);
thread::Builder::new() thread::Builder::new()
.name("apis".to_string()) .name("apis".to_string())
.spawn(move || { .spawn(move || {
let server = async move { let server = async move {
let server = Server::bind(&addr).serve(make_service_fn(move |_| { let server = Server::bind(&addr)
.serve(make_service_fn(move |_| {
let router = router.clone(); let router = router.clone();
async move { Ok::<_, Infallible>(router) } async move { Ok::<_, Infallible>(router) }
})); }))
// TODO graceful shutdown is unstable, investigate .with_graceful_shutdown(async {
//.with_graceful_shutdown(rx) rx.await.ok();
});
server.await server.await
}; };
@ -239,7 +241,7 @@ impl ApiServer {
router: Router, router: Router,
conf: TLSConfig, conf: TLSConfig,
) -> Result<thread::JoinHandle<()>, Error> { ) -> Result<thread::JoinHandle<()>, Error> {
if self.shutdown_sender.is_some() { if self.is_running() {
return Err(ErrorKind::Internal( return Err(ErrorKind::Internal(
"Can't start HTTPS API server, it's running already".to_string(), "Can't start HTTPS API server, it's running already".to_string(),
) )
@ -280,10 +282,9 @@ impl ApiServer {
/// Stops the API server, it panics in case of error /// Stops the API server, it panics in case of error
pub fn stop(&mut self) -> bool { pub fn stop(&mut self) -> bool {
if self.shutdown_sender.is_some() { if self.is_running() {
// TODO re-enable stop after investigation let tx = mem::replace(&mut self.shutdown_sender, None).unwrap();
//let tx = mem::replace(&mut self.shutdown_sender, None).unwrap(); tx.send(()).expect("Failed to stop API server");
//tx.send(()).expect("Failed to stop API server");
info!("API server has been stopped"); info!("API server has been stopped");
true true
} else { } else {
@ -291,6 +292,10 @@ impl ApiServer {
false false
} }
} }
pub fn is_running(&self) -> bool {
self.shutdown_sender.is_some()
}
} }
pub struct LoggingMiddleware {} pub struct LoggingMiddleware {}

View file

@ -78,6 +78,7 @@ fn test_start_api() {
assert_eq!(counter.value(), 1); assert_eq!(counter.value(), 1);
assert!(server.stop()); assert!(server.stop());
thread::sleep(time::Duration::from_millis(1_000)); thread::sleep(time::Duration::from_millis(1_000));
assert!(!server.is_running());
} }
// To enable this test you need a trusted PKCS12 (p12) certificate bundle // To enable this test you need a trusted PKCS12 (p12) certificate bundle
@ -100,6 +101,8 @@ fn test_start_api_tls() {
let index = request_with_retry("https://yourdomain.com:14444/v1/").unwrap(); let index = request_with_retry("https://yourdomain.com:14444/v1/").unwrap();
assert_eq!(index.len(), 2); assert_eq!(index.len(), 2);
assert!(!server.stop()); assert!(!server.stop());
thread::sleep(time::Duration::from_millis(1_000));
assert!(!server.is_running());
} }
fn request_with_retry(url: &str) -> Result<Vec<String>, api::Error> { fn request_with_retry(url: &str) -> Result<Vec<String>, api::Error> {