Skip to content

Commit ab0252b

Browse files
committed
fix shutdown
Signed-off-by: Lee Benson <lee@leebenson.com>
1 parent 9d4048d commit ab0252b

File tree

1 file changed

+31
-33
lines changed

1 file changed

+31
-33
lines changed

src/api/tap.rs

+31-33
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::{ShutdownRx, ShutdownTx};
2+
use crate::topology::fanout::ControlChannel;
23
use crate::{
34
event::{Event, LogEvent},
45
topology::{fanout, WatchRx},
@@ -93,29 +94,41 @@ async fn send_not_matched(mut tx: TapSender, pattern: &str) -> Result<(), SendEr
9394
}
9495

9596
/// Makes a `RouterSink` that relays `Log` as `TapPayload::Log` to a client.
96-
fn make_router(mut tx: TapSender, component_name: &str) -> fanout::RouterSink {
97+
fn make_router(
98+
mut tx: TapSender,
99+
control_tx: ControlChannel,
100+
sink_id: String,
101+
component_name: String,
102+
) -> (fanout::RouterSink, ShutdownTx) {
103+
let (shutdown_tx, mut shutdown_rx) = oneshot::channel();
97104
let (event_tx, mut event_rx) = futures_mpsc::unbounded();
98-
let component_name = component_name.to_string();
99105

100106
tokio::spawn(async move {
101107
debug!(message = "Spawned event handler.", component_name = ?component_name);
102108

103-
while let Some(ev) = event_rx.next().await {
104-
if let Event::Log(ev) = ev {
105-
if let Err(err) = tx.send(TapPayload::Log(component_name.clone(), ev)).await {
106-
debug!(
107-
message = "Couldn't send log event.",
108-
error = ?err,
109-
component_name = ?component_name);
109+
loop {
110+
tokio::select! {
111+
_ = &mut shutdown_rx => {
112+
let _ = control_tx.send(fanout::ControlMessage::Remove(sink_id.to_string()));
110113
break;
114+
},
115+
Some(ev) = event_rx.next() => {
116+
if let Event::Log(ev) = ev {
117+
if let Err(err) = tx.send(TapPayload::Log(component_name.clone(), ev)).await {
118+
debug!(
119+
message = "Couldn't send log event.",
120+
error = ?err,
121+
component_name = ?component_name);
122+
}
123+
}
111124
}
112125
}
113126
}
114127

115128
debug!(message = "Stopped event handler.", component_name = ?component_name);
116129
});
117130

118-
Box::new(event_tx.sink_map_err(|_| ()))
131+
(Box::new(event_tx.sink_map_err(|_| ())), shutdown_tx)
119132
}
120133

121134
/// Returns a tap handler that listens for topology changes, and connects sinks to observe
@@ -131,9 +144,6 @@ async fn tap_handler(
131144
// Sinks register for the current tap. Will be updated as new components match.
132145
let mut sinks = HashMap::new();
133146

134-
// Keep a copy of the last topology snapshot, for later clean-up.
135-
let mut last_outputs = None;
136-
137147
loop {
138148
tokio::select! {
139149
_ = &mut shutdown_rx => break,
@@ -164,16 +174,22 @@ async fn tap_handler(
164174
// reconfigured with the same name as a previous, and we are not
165175
// getting involved in config diffing at this point.
166176
let id = Uuid::new_v4().to_string();
167-
let sink = make_router(tx.clone(), name);
177+
let (sink, shutdown_tx) = make_router(
178+
tx.clone(),
179+
control_tx.clone(),
180+
id.to_string(),
181+
name.to_string(),
182+
);
168183

169184
match control_tx.send(fanout::ControlMessage::Add(id.to_string(), sink)) {
170185
Ok(_) => {
171186
// (Over)write the sink entry.
187+
sinks.insert(name.to_string(), shutdown_tx);
188+
172189
debug!(
173190
message = "Component connected.",
174191
component_name = ?name, id = ?id
175192
);
176-
sinks.insert(name.to_string(), id);
177193
}
178194
Err(err) => {
179195
error!(
@@ -206,9 +222,6 @@ async fn tap_handler(
206222
}
207223
});
208224

209-
// Keep the outputs for later clean-up when a shutdown is triggered.
210-
last_outputs = Some(outputs);
211-
212225
// Send notifications to the client. The # of notifications will always be
213226
// exactly equal to the number of patterns, so we can pre-allocate capacity.
214227
let mut notifications = Vec::with_capacity(patterns.len());
@@ -233,21 +246,6 @@ async fn tap_handler(
233246
}
234247
}
235248

236-
// At this point, the tap handler is being shut down due to the client/subscription
237-
// going away. Clean up tap sinks by disconnecting them from the components being observed.
238-
if let Some(outputs) = last_outputs {
239-
for (name, id) in sinks {
240-
if let Some(control_tx) = outputs.get(&name) {
241-
if let Err(err) = control_tx.send(fanout::ControlMessage::Remove(id)) {
242-
error!(
243-
message = "Couldn't disconnect tap sink.",
244-
error = ?err,
245-
component_name = ?name);
246-
}
247-
}
248-
}
249-
}
250-
251249
debug!(message = "Stopped tap.", patterns = ?patterns);
252250
}
253251

0 commit comments

Comments
 (0)