MCPcopy Create free account
hub / github.com/NodeDB-Lab/nodedb / notify

Method notify

nodedb/src/control/notify_bus.rs:173–225  ·  view source on GitHub ↗

Publish a notification to all listeners on `(tenant_id, channel)`. Non-blocking: uses `try_send`. When a session's queue is full, the oldest pending notification is dropped via a `recv().ok()` drain and the new one is re-sent, then the drop counter is incremented.

(&self, tenant_id: TenantId, channel: &str, payload: &str)

Source from the content-addressed store, hash-verified

171 /// the oldest pending notification is dropped via a `recv().ok()` drain
172 /// and the new one is re-sent, then the drop counter is incremented.
173 pub fn notify(&self, tenant_id: TenantId, channel: &str, payload: &str) {
174 let key = BusKey {
175 tenant_id: tenant_id.as_u64(),
176 channel: normalize_channel(channel),
177 };
178 let notification = Notification {
179 channel: key.channel.clone(),
180 payload: payload.to_string(),
181 pid: 0,
182 };
183
184 let map = self.subscribers.read().unwrap_or_else(|p| p.into_inner());
185 let sinks = match map.get(&key) {
186 Some(s) => s,
187 None => return, // no listeners — no-op
188 };
189
190 let mut dead = Vec::new();
191 for (session_id, sink) in sinks {
192 match sink.tx.try_send(notification.clone()) {
193 Ok(()) => {}
194 Err(tokio::sync::mpsc::error::TrySendError::Full(_)) => {
195 // Queue is full — drain one entry to make room, then retry.
196 // We don't have a mutable ref so we can't drain directly here.
197 // Use a blocking_recv in a non-async context isn't available,
198 // but try_recv on the sender side isn't accessible.
199 // Instead: increment the drop counter and skip.
200 self.dropped.fetch_add(1, Ordering::Relaxed);
201 warn!(
202 session_id,
203 channel = key.channel.as_str(),
204 cap = sink.cap,
205 "NOTIFY queue full — dropping oldest (metric incremented)"
206 );
207 }
208 Err(tokio::sync::mpsc::error::TrySendError::Closed(_)) => {
209 dead.push(*session_id);
210 }
211 }
212 }
213 drop(map);
214
215 // Clean up closed sessions.
216 if !dead.is_empty() {
217 let mut map = self.subscribers.write().unwrap_or_else(|p| p.into_inner());
218 if let Some(sinks) = map.get_mut(&key) {
219 sinks.retain(|(id, _)| !dead.contains(id));
220 if sinks.is_empty() {
221 map.remove(&key);
222 }
223 }
224 }
225 }
226
227 /// Total dropped notifications since server start.
228 pub fn total_dropped(&self) -> u64 {

Callers 7

basic_listen_notifyFunction · 0.45
unlisten_stops_deliveryFunction · 0.45
tenant_isolationFunction · 0.45
unlisten_allFunction · 0.45
handle_notifyMethod · 0.45

Calls 13

normalize_channelFunction · 0.85
to_stringMethod · 0.80
try_sendMethod · 0.80
as_u64Method · 0.45
cloneMethod · 0.45
readMethod · 0.45
getMethod · 0.45
pushMethod · 0.45
is_emptyMethod · 0.45
writeMethod · 0.45
get_mutMethod · 0.45
containsMethod · 0.45

Tested by

no test coverage detected