Skip to content

Commit df4880c

Browse files
committed
Add server shutdown logic
also change Dockerfile server start from `CMD` to `ENTRYPOINT`
1 parent 5430009 commit df4880c

File tree

5 files changed

+72
-16
lines changed

5 files changed

+72
-16
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ tokio = { version = "1.45.0", features = [
1313
"rt-multi-thread",
1414
"net",
1515
"io-util",
16+
"signal",
1617
] }
1718
serde = { version = "1.0.219", features = ["derive"] }
1819
serde_json = "1.0.140"

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ FROM gcr.io/distroless/cc:latest
2020
COPY --from=builder /code/target/release/server /usr/local/bin/server
2121

2222
# start server
23-
CMD [ "/usr/local/bin/server" ]
23+
ENTRYPOINT [ "/usr/local/bin/server" ]

src/main.rs

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ mod config;
22
mod models;
33
mod protocol;
44
mod server;
5+
mod shutdown;
56

67
use config::Config;
8+
use shutdown::Shutdown;
79
use std::{env, io};
8-
use tokio::net::TcpListener;
10+
use tokio::{net::TcpListener, select};
911
use tracing::{debug, info, info_span, Instrument};
1012
use tracing_subscriber::EnvFilter;
1113

@@ -39,24 +41,37 @@ async fn main() -> io::Result<()> {
3941
let listener = TcpListener::bind(format!("{}:{}", config.host, config.port)).await?;
4042
info!("Server listening on port {}", config.port);
4143

44+
let mut shutdown = Shutdown::new()?;
45+
4246
loop {
43-
match listener.accept().await {
44-
Ok((stream, addr)) => {
45-
debug!("New connection from: {}", addr);
46-
47-
let config = config.clone();
48-
tokio::spawn(
49-
async move {
50-
if let Err(e) = server::handle_client(stream, config).await {
51-
debug!("Error handling client: {}", e);
52-
}
47+
select! {
48+
conn = listener.accept() => {
49+
match conn {
50+
Ok((stream, addr)) => {
51+
debug!("New connection from: {}", addr);
52+
53+
let config = config.clone();
54+
tokio::spawn(
55+
async move {
56+
if let Err(e) = server::handle_client(stream, config).await {
57+
debug!("Error handling client: {}", e);
58+
}
59+
}
60+
.instrument(info_span!("client", "{}", addr)),
61+
);
62+
}
63+
Err(e) => {
64+
debug!("Error accepting connection: {}", e);
5365
}
54-
.instrument(info_span!("client", "{}", addr)),
55-
);
66+
}
5667
}
57-
Err(e) => {
58-
debug!("Error accepting connection: {}", e);
68+
69+
_ = shutdown.wait_for_shutdown() => {
70+
break;
5971
}
6072
}
6173
}
74+
75+
info!("Shutting down server...");
76+
Ok(())
6277
}

src/shutdown.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use std::io;
2+
use tokio::{select, signal};
3+
4+
#[cfg(unix)]
5+
use tokio::signal::unix::{signal, SignalKind};
6+
7+
pub struct Shutdown {
8+
#[cfg(unix)]
9+
sigterm: tokio::signal::unix::Signal,
10+
}
11+
impl Shutdown {
12+
pub fn new() -> io::Result<Self> {
13+
Ok(Self {
14+
#[cfg(unix)]
15+
sigterm: signal(SignalKind::terminate())?,
16+
})
17+
}
18+
19+
pub async fn wait_for_shutdown(&mut self) {
20+
#[cfg(unix)]
21+
let unix_signal = self.sigterm.recv();
22+
#[cfg(not(unix))]
23+
let unix_signal = std::future::pending::<()>();
24+
25+
select! {
26+
_ = signal::ctrl_c() => {},
27+
_ = unix_signal => {},
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)