fix(room): fix two major memory leaks
1. WS disconnect now unsubscribes from user_notification_inner. Previously, every WebSocket connection created a broadcast channel for user notifications that was never removed on disconnect, causing unbounded growth proportional to unique connected users over time. 2. Room worker tasks now use the manager's room_shutdown_txs channel instead of a local broadcast channel. shutdown_room() sends on this channel, so when a room is deleted the worker task receives the signal and terminates, releasing its DashMap (capacity 10,000) and all captured closures. Previously the worker ran forever.
This commit is contained in:
parent
15483b4e95
commit
0e53f4a69f
@ -445,6 +445,7 @@ pub async fn ws_universal(
|
|||||||
for room_id in push_streams.keys() {
|
for room_id in push_streams.keys() {
|
||||||
manager.unsubscribe(*room_id, user_id).await;
|
manager.unsubscribe(*room_id, user_id).await;
|
||||||
}
|
}
|
||||||
|
manager.unsubscribe_user_notification(user_id).await;
|
||||||
manager.metrics.ws_connections_active.decrement(1.0);
|
manager.metrics.ws_connections_active.decrement(1.0);
|
||||||
manager.metrics.ws_disconnections_total.increment(1);
|
manager.metrics.ws_disconnections_total.increment(1);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -270,19 +270,21 @@ pub fn spawn_room_workers(
|
|||||||
);
|
);
|
||||||
let get_redis: Arc<dyn Fn() -> queue::worker::RedisFuture + Send + Sync> =
|
let get_redis: Arc<dyn Fn() -> queue::worker::RedisFuture + Send + Sync> =
|
||||||
extract_get_redis(queue.clone());
|
extract_get_redis(queue.clone());
|
||||||
let manager = room_manager.clone();
|
let manager1 = room_manager.clone();
|
||||||
let redis_url_clone = redis_url.clone();
|
|
||||||
let semaphore = worker_semaphore.clone();
|
|
||||||
|
|
||||||
let manager2 = room_manager.clone();
|
let manager2 = room_manager.clone();
|
||||||
|
let manager3 = room_manager.clone();
|
||||||
|
let redis_url_clone = redis_url.clone();
|
||||||
let redis_url3 = redis_url.clone();
|
let redis_url3 = redis_url.clone();
|
||||||
|
let semaphore = worker_semaphore.clone();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let _permit = match semaphore.acquire_owned().await {
|
let _permit = match semaphore.acquire_owned().await {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
let (shutdown_tx, shutdown_rx) = tokio::sync::broadcast::channel::<()>(1);
|
// Use the manager's room shutdown channel so the worker terminates
|
||||||
|
// when the room is deleted (shutdown_room sends on room_shutdown_txs).
|
||||||
|
let shutdown_rx = manager1.register_room(room_id).await;
|
||||||
queue::room_worker_task(
|
queue::room_worker_task(
|
||||||
room_id,
|
room_id,
|
||||||
uuid::Uuid::new_v4().to_string(),
|
uuid::Uuid::new_v4().to_string(),
|
||||||
@ -291,14 +293,13 @@ pub fn spawn_room_workers(
|
|||||||
shutdown_rx,
|
shutdown_rx,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
let _ = shutdown_tx.send(());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let shutdown_rx = manager.register_room(room_id).await;
|
let shutdown_rx = manager2.register_room(room_id).await;
|
||||||
crate::connection::subscribe_room_events(
|
crate::connection::subscribe_room_events(
|
||||||
redis_url_clone,
|
redis_url_clone,
|
||||||
manager.clone(),
|
manager2,
|
||||||
room_id,
|
room_id,
|
||||||
shutdown_rx,
|
shutdown_rx,
|
||||||
)
|
)
|
||||||
@ -317,10 +318,10 @@ pub fn spawn_room_workers(
|
|||||||
None => return,
|
None => return,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let shutdown_rx = manager2.register_project(project_id).await;
|
let shutdown_rx = manager3.register_project(project_id).await;
|
||||||
crate::connection::subscribe_project_room_events(
|
crate::connection::subscribe_project_room_events(
|
||||||
redis_url3,
|
redis_url3,
|
||||||
manager2,
|
manager3,
|
||||||
project_id,
|
project_id,
|
||||||
shutdown_rx,
|
shutdown_rx,
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user