-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementing graceful shutdown #105
Changes from 6 commits
dba369a
72c6622
aa593ed
029429d
67a81f3
d667b17
324b539
6ed4eb1
f667e7a
78a1d70
3737f06
b01b54c
cec0f1f
863ba8c
335ad62
df08b7f
35d3346
ab4e669
72d7492
e1620dd
b018f41
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
.idea | ||
/target | ||
*.deb | ||
.vscode |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,17 +36,17 @@ extern crate tokio; | |
extern crate tokio_rustls; | ||
extern crate toml; | ||
|
||
use log::{debug, error, info}; | ||
use log::{debug, error, info, warn}; | ||
use parking_lot::Mutex; | ||
use tokio::net::TcpListener; | ||
use tokio::{ | ||
signal, | ||
signal::unix::{signal as unix_signal, SignalKind}, | ||
sync::mpsc, | ||
}; | ||
|
||
use std::collections::HashMap; | ||
use std::sync::Arc; | ||
use tokio::sync::broadcast; | ||
|
||
mod admin; | ||
mod client; | ||
|
@@ -139,24 +139,51 @@ async fn main() { | |
|
||
info!("Waiting for clients"); | ||
|
||
let (shutdown_event_tx, mut shutdown_event_rx) = broadcast::channel::<()>(1); | ||
|
||
let shutdown_event_tx_clone = shutdown_event_tx.clone(); | ||
|
||
// Client connection loop. | ||
tokio::task::spawn(async move { | ||
// Creates event subscriber for shutdown event, this is dropped when shutdown event is broadcast | ||
let mut listener_rx = shutdown_event_tx_clone.subscribe(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please rename to shutdown_event_rx because it can be confused with TCP listener by the reader. |
||
loop { | ||
let client_server_map = client_server_map.clone(); | ||
|
||
let (socket, addr) = match listener.accept().await { | ||
Ok((socket, addr)) => (socket, addr), | ||
Err(err) => { | ||
error!("{:?}", err); | ||
continue; | ||
// Listen for shutdown event and client connection at the same time | ||
let (socket, addr) = tokio::select! { | ||
_ = listener_rx.recv() => { | ||
break; | ||
} | ||
|
||
listener_response = listener.accept() => { | ||
match listener_response { | ||
Ok((socket, addr)) => (socket, addr), | ||
Err(err) => { | ||
error!("{:?}", err); | ||
continue; | ||
} | ||
} | ||
} | ||
}; | ||
|
||
// Used to signal shutdown | ||
let client_shutdown_handler_rx = shutdown_event_tx_clone.subscribe(); | ||
|
||
// Used to signal that the task has completed | ||
let dummy_tx = shutdown_event_tx_clone.clone(); | ||
|
||
// Handle client. | ||
tokio::task::spawn(async move { | ||
let start = chrono::offset::Utc::now().naive_utc(); | ||
|
||
match client::client_entrypoint(socket, client_server_map).await { | ||
match client::client_entrypoint( | ||
socket, | ||
client_server_map, | ||
client_shutdown_handler_rx, | ||
) | ||
.await | ||
{ | ||
Ok(_) => { | ||
let duration = chrono::offset::Utc::now().naive_utc() - start; | ||
|
||
|
@@ -171,6 +198,8 @@ async fn main() { | |
debug!("Client disconnected with error {:?}", err); | ||
} | ||
}; | ||
// Drop this transmitter so receiver knows that the task is completed | ||
drop(dummy_tx); | ||
}); | ||
} | ||
}); | ||
|
@@ -214,15 +243,25 @@ async fn main() { | |
}); | ||
} | ||
|
||
// Exit on Ctrl-C (SIGINT) and SIGTERM. | ||
let mut term_signal = unix_signal(SignalKind::terminate()).unwrap(); | ||
// Initiate graceful shutdown sequence on sig int | ||
let mut stream = unix_signal(SignalKind::interrupt()).unwrap(); | ||
|
||
tokio::select! { | ||
_ = signal::ctrl_c() => (), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Curious why you removed the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pgbouncer interprets sigterm and sigint differently. since the sigint is graceful shutdown we want to catch and handle that. for sigterm, which is immediate shutdown we don't need to do anything special
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm curious about the reasoning here. In Kuberentes SIGTERM is meant to initiate a graceful shutdown. https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/ |
||
_ = term_signal.recv() => (), | ||
}; | ||
stream.recv().await; | ||
warn!("Got SIGINT, waiting for client connection drain now"); | ||
|
||
info!("Shutting down..."); | ||
// Broadcast that client tasks need to finish | ||
shutdown_event_tx.send(()).unwrap(); | ||
// Closes transmitter | ||
drop(shutdown_event_tx); | ||
|
||
loop { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you looping? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There should be two events that the receiver gets, the 1st is the event sent by |
||
match shutdown_event_rx.recv().await { | ||
// The first event the receiver gets is from the initial broadcast, so we ignore that | ||
Ok(_) => {} | ||
// Expect to receive a closed error when all transmitters are closed. Which means all clients have completed their work | ||
Err(_) => break, | ||
}; | ||
} | ||
} | ||
|
||
/// Format chrono::Duration to be more human-friendly. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add a terminal new line