Skip to content

Commit 81541f7

Browse files
committed
Handle sigint and sigterm
1 parent 6b96c5f commit 81541f7

9 files changed

Lines changed: 95 additions & 39 deletions

File tree

pixie-server/Cargo.lock

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

pixie-server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ http-body-util = "0.1.3"
2828
futures = "0.3.30"
2929
tokio-stream = { version = "0.1.17", features = ["sync"] }
3030
chrono = "0.4.41"
31+
tokio-util = "0.7.15"
3132

3233
[dependencies.pixie-shared]
3334
path = "../pixie-shared"

pixie-server/src/dnsmasq.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ pub async fn main(state: Arc<State>) -> Result<()> {
139139
tokio::select! {
140140
ret = units_rx.changed() => ret.unwrap(),
141141
ret = hostmap_rx.changed() => ret.unwrap(),
142+
_ = state.cancel_token.cancelled() => break,
142143
}
143144

144145
let hosts2 = get_hosts(
@@ -151,4 +152,5 @@ pub async fn main(state: Arc<State>) -> Result<()> {
151152
dnsmasq.reload()?;
152153
}
153154
}
155+
Ok(())
154156
}

pixie-server/src/http.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,15 @@ async fn status(extract::State(state): extract::State<Arc<State>>) -> impl IntoR
162162
let image_rx = WatchStream::new(state.subscribe_images());
163163
let hostmap_rx = WatchStream::new(state.subscribe_hostmap());
164164

165-
let messages = futures::stream::iter(initial_messages).chain(futures::stream::select(
166-
futures::stream::select(
167-
image_rx.map(StatusUpdate::ImagesStats),
168-
units_rx.map(StatusUpdate::Units),
169-
),
170-
hostmap_rx.map(StatusUpdate::HostMap),
171-
));
165+
let messages = futures::stream::iter(initial_messages)
166+
.chain(futures::stream::select(
167+
futures::stream::select(
168+
image_rx.map(StatusUpdate::ImagesStats),
169+
units_rx.map(StatusUpdate::Units),
170+
),
171+
hostmap_rx.map(StatusUpdate::HostMap),
172+
))
173+
.take_until(state.cancel_token.clone().cancelled_owned());
172174
let lines = messages.map(|msg| serde_json::to_string(&msg).map(|x| x + "\n"));
173175

174176
Response::builder()
@@ -208,8 +210,11 @@ pub async fn main(state: Arc<State>) -> Result<()> {
208210
}
209211
router = router.layer(TraceLayer::new_for_http());
210212

213+
let shutdown_token = state.cancel_token.clone().cancelled_owned();
211214
let listener = TcpListener::bind(listen_on).await?;
212-
axum::serve(listener, router.with_state(state)).await?;
215+
axum::serve(listener, router.with_state(state))
216+
.with_graceful_shutdown(shutdown_token)
217+
.await?;
213218

214219
Ok(())
215220
}

pixie-server/src/main.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use std::{
1919
process::{Child, Command, Stdio},
2020
sync::Arc,
2121
};
22-
use tokio::task::JoinHandle;
22+
use tokio::{signal::unix::SignalKind, task::JoinHandle};
2323

2424
/// Finds the mac address for the given ip.
2525
///
@@ -130,11 +130,26 @@ async fn main() -> Result<()> {
130130

131131
let state = Arc::new(State::load(options.storage_dir)?);
132132

133+
tokio::spawn({
134+
let cancel_token = state.cancel_token.clone();
135+
let mut sigint = tokio::signal::unix::signal(SignalKind::interrupt())
136+
.expect("failed to register SIGNINT handler");
137+
let mut sigterm = tokio::signal::unix::signal(SignalKind::terminate())
138+
.expect("failed to register SIGNTERM handler");
139+
async move {
140+
let _token_guard = cancel_token.drop_guard();
141+
tokio::select! {
142+
_ = sigint.recv() => log::info!("Received SIGINT."),
143+
_ = sigterm.recv() => log::info!("Received SIGTERM."),
144+
};
145+
}
146+
});
147+
133148
let state2 = state.clone();
134149
tokio::spawn(async move {
135-
let mut signal = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::hangup())
136-
.expect("failed to register signal handler");
137-
while let Some(()) = signal.recv().await {
150+
let mut sighup = tokio::signal::unix::signal(SignalKind::hangup())
151+
.expect("failed to register SIGHUP handler");
152+
while let Some(()) = sighup.recv().await {
138153
state2.reload().unwrap();
139154
}
140155
});

pixie-server/src/ping.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ pub async fn main(state: Arc<State>) -> Result<()> {
1919

2020
let mut buf = [0; PACKET_LEN];
2121
loop {
22-
let (len, peer_addr) = socket.recv_from(&mut buf).await?;
22+
let (len, peer_addr) = tokio::select! {
23+
x = socket.recv_from(&mut buf) => x?,
24+
_ = state.cancel_token.cancelled() => break,
25+
};
2326
let IpAddr::V4(peer_ip) = peer_addr.ip() else {
2427
bail!("IPv6 is not supported")
2528
};
@@ -37,4 +40,5 @@ pub async fn main(state: Arc<State>) -> Result<()> {
3740
.as_secs();
3841
state.set_unit_ping(UnitSelector::MacAddr(peer_mac), time, &buf[..len]);
3942
}
43+
Ok(())
4044
}

pixie-server/src/state/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use std::{
2929
},
3030
};
3131
use tokio::sync::watch;
32+
use tokio_util::sync::CancellationToken;
3233

3334
pub use units::UnitSelector;
3435

@@ -99,6 +100,9 @@ pub struct State {
99100
registration_hint: Mutex<Option<RegistrationInfo>>,
100101
images_stats: watch::Sender<ImagesStats>,
101102
chunks_stats: Mutex<ChunksStats>,
103+
104+
/// Token to shutdown the entire server.
105+
pub cancel_token: CancellationToken,
102106
}
103107

104108
impl State {
@@ -206,6 +210,8 @@ impl State {
206210
let run_dir = PathBuf::from(format!("/run/pixie-{}", std::process::id()));
207211
std::fs::create_dir(&run_dir)?;
208212

213+
let cancel_token = CancellationToken::new();
214+
209215
Ok(Self {
210216
storage_dir,
211217
run_dir,
@@ -215,6 +221,7 @@ impl State {
215221
registration_hint: Mutex::new(None),
216222
images_stats: watch::Sender::new(images_stats),
217223
chunks_stats: Mutex::new(chunks_stats),
224+
cancel_token,
218225
})
219226
}
220227

pixie-server/src/tcp.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,16 @@ pub async fn main(state: Arc<State>) -> Result<()> {
8787
let listener = TcpListener::bind((Ipv4Addr::UNSPECIFIED, ACTION_PORT)).await?;
8888
log::info!("Listening on {}", listener.local_addr()?);
8989
loop {
90-
let (stream, addr) = listener.accept().await?;
90+
let (stream, addr) = tokio::select! {
91+
x = listener.accept() => x?,
92+
_ = state.cancel_token.cancelled() => break,
93+
};
9194
let state = state.clone();
9295
tokio::spawn(async move {
9396
if let Err(e) = handle_connection(state, stream, addr).await {
9497
log::error!("Error handling tcp connection: {}", e);
9598
}
9699
});
97100
}
101+
Ok(())
98102
}

pixie-server/src/udp.rs

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,25 +33,34 @@ async fn broadcast_chunks(
3333
let mut index = [0; 32];
3434

3535
loop {
36-
while let Ok(hash) = rx.try_recv() {
37-
queue.insert(hash);
38-
}
36+
let get_index = async {
37+
while let Ok(hash) = rx.try_recv() {
38+
queue.insert(hash);
39+
}
40+
41+
let hash = queue
42+
.range((Bound::Excluded(index), Bound::Unbounded))
43+
.next()
44+
.or_else(|| queue.iter().next())
45+
.copied();
3946

40-
let hash = queue
41-
.range((Bound::Excluded(index), Bound::Unbounded))
42-
.next()
43-
.or_else(|| queue.iter().next())
44-
.copied();
47+
match hash {
48+
Some(hash) => {
49+
queue.remove(&hash);
50+
Some(hash)
51+
}
52+
None => rx.recv().await,
53+
}
54+
};
4555

46-
index = match hash {
47-
Some(hash) => {
48-
queue.remove(&hash);
49-
hash
56+
tokio::select! {
57+
hash = get_index => {
58+
let Some(hash) = hash else {
59+
break;
60+
};
61+
index = hash;
5062
}
51-
None => match rx.recv().await {
52-
Some(hash) => hash,
53-
None => break,
54-
},
63+
_ = state.cancel_token.cancelled() => break,
5564
};
5665

5766
let Some(data) = state
@@ -162,6 +171,10 @@ fn compute_hint(state: &State) -> Result<RegistrationInfo> {
162171

163172
async fn broadcast_hint(state: &State, socket: &UdpSocket, ip: Ipv4Addr) -> Result<()> {
164173
loop {
174+
tokio::select! {
175+
_ = time::sleep(Duration::from_secs(1)) => {}
176+
_ = state.cancel_token.cancelled() => break,
177+
}
165178
let hint = HintPacket {
166179
station: compute_hint(state)?,
167180
images: state.config.images.clone(),
@@ -170,14 +183,17 @@ async fn broadcast_hint(state: &State, socket: &UdpSocket, ip: Ipv4Addr) -> Resu
170183
let data = postcard::to_allocvec(&hint)?;
171184
let hint_addr = SocketAddrV4::new(ip, HINT_PORT);
172185
socket.send_to(&data, hint_addr).await?;
173-
time::sleep(Duration::from_secs(1)).await;
174186
}
187+
Ok(())
175188
}
176189

177190
async fn handle_requests(state: &State, socket: &UdpSocket, tx: Sender<[u8; 32]>) -> Result<()> {
178191
let mut buf = [0; PACKET_LEN];
179-
'recv_packet: loop {
180-
let (len, addr) = socket.recv_from(&mut buf).await?;
192+
loop {
193+
let (len, addr) = tokio::select! {
194+
x = socket.recv_from(&mut buf) => x?,
195+
_ = state.cancel_token.cancelled() => break,
196+
};
181197
let req: postcard::Result<UdpRequest> = postcard::from_bytes(&buf[..len]);
182198
match req {
183199
Ok(UdpRequest::Discover) => {
@@ -187,14 +203,14 @@ async fn handle_requests(state: &State, socket: &UdpSocket, tx: Sender<[u8; 32]>
187203
let IpAddr::V4(peer_ip) = addr.ip() else {
188204
bail!("IPv6 is not supported")
189205
};
190-
let peer_mac = match find_mac(peer_ip) {
191-
Ok(peer_mac) => peer_mac,
206+
match find_mac(peer_ip) {
207+
Ok(peer_mac) => {
208+
state.set_unit_progress(UnitSelector::MacAddr(peer_mac), Some((frac, tot)));
209+
}
192210
Err(err) => {
193211
log::error!("Error handling udp packet: {}", err);
194-
continue 'recv_packet;
195212
}
196213
};
197-
state.set_unit_progress(UnitSelector::MacAddr(peer_mac), Some((frac, tot)));
198214
}
199215
Ok(UdpRequest::RequestChunks(chunks)) => {
200216
for hash in chunks {
@@ -206,6 +222,7 @@ async fn handle_requests(state: &State, socket: &UdpSocket, tx: Sender<[u8; 32]>
206222
}
207223
}
208224
}
225+
Ok(())
209226
}
210227

211228
pub async fn main(state: Arc<State>) -> Result<()> {

0 commit comments

Comments
 (0)