1- use std:: collections:: VecDeque ;
21use std:: mem;
32use std:: pin:: { pin, Pin } ;
43use std:: time:: Duration ;
@@ -15,7 +14,10 @@ use http::{HeaderValue, StatusCode};
1514use scopeguard:: ScopeGuard ;
1615use serde:: Deserialize ;
1716use spacetimedb:: client:: messages:: { serialize, IdentityTokenMessage , SerializableMessage , SerializeBuffer } ;
18- use spacetimedb:: client:: { ClientActorId , ClientConfig , ClientConnection , DataMessage , MessageHandleError , Protocol } ;
17+ use spacetimedb:: client:: {
18+ ClientActorId , ClientConfig , ClientConnection , DataMessage , MessageHandleError , MeteredDeque , MeteredReceiver ,
19+ Protocol ,
20+ } ;
1921use spacetimedb:: execution_context:: WorkloadType ;
2022use spacetimedb:: host:: module_host:: ClientConnectedError ;
2123use spacetimedb:: host:: NoSuchModule ;
@@ -25,7 +27,6 @@ use spacetimedb::Identity;
2527use spacetimedb_client_api_messages:: websocket:: { self as ws_api, Compression } ;
2628use spacetimedb_lib:: connection_id:: { ConnectionId , ConnectionIdForUrl } ;
2729use std:: time:: Instant ;
28- use tokio:: sync:: mpsc;
2930use tokio_tungstenite:: tungstenite:: Utf8Bytes ;
3031
3132use crate :: auth:: SpacetimeAuth ;
@@ -182,7 +183,7 @@ where
182183
183184const LIVELINESS_TIMEOUT : Duration = Duration :: from_secs ( 60 ) ;
184185
185- async fn ws_client_actor ( client : ClientConnection , ws : WebSocketStream , sendrx : mpsc :: Receiver < SerializableMessage > ) {
186+ async fn ws_client_actor ( client : ClientConnection , ws : WebSocketStream , sendrx : MeteredReceiver < SerializableMessage > ) {
186187 // ensure that even if this task gets cancelled, we always cleanup the connection
187188 let mut client = scopeguard:: guard ( client, |client| {
188189 tokio:: spawn ( client. disconnect ( ) ) ;
@@ -204,11 +205,13 @@ async fn make_progress<Fut: Future>(fut: &mut Pin<&mut MaybeDone<Fut>>) {
204205async fn ws_client_actor_inner (
205206 client : & mut ClientConnection ,
206207 mut ws : WebSocketStream ,
207- mut sendrx : mpsc :: Receiver < SerializableMessage > ,
208+ mut sendrx : MeteredReceiver < SerializableMessage > ,
208209) {
209210 let mut liveness_check_interval = tokio:: time:: interval ( LIVELINESS_TIMEOUT ) ;
210211 let mut got_pong = true ;
211212
213+ let addr = client. module . info ( ) . database_identity ;
214+
212215 // Build a queue of incoming messages to handle, to be processed one at a time,
213216 // in the order they're received.
214217 //
@@ -222,32 +225,14 @@ async fn ws_client_actor_inner(
222225 // `select!` for examples of how to do this.
223226 //
224227 // TODO: do we want this to have a fixed capacity? or should it be unbounded
225- let mut message_queue = VecDeque :: < ( DataMessage , Instant ) > :: new ( ) ;
228+ let mut message_queue = MeteredDeque :: < ( DataMessage , Instant ) > :: new (
229+ WORKER_METRICS . total_incoming_queue_length . with_label_values ( & addr) ,
230+ ) ;
226231 let mut current_message = pin ! ( MaybeDone :: Gone ) ;
227232
228233 let mut closed = false ;
229234 let mut rx_buf = Vec :: new ( ) ;
230235
231- let addr = client. module . info ( ) . database_identity ;
232-
233- // Grab handles on the total incoming and outgoing queue length metrics,
234- // which we'll increment and decrement as we push into and pull out of those queues.
235- // Note that `total_outgoing_queue_length` is incremented separately,
236- // by `ClientConnectionSender::send` in core/src/client/client_connection.rs;
237- // we're only responsible for decrementing that one.
238- // Also note that much care must be taken to clean up these metrics when the connection closes!
239- // Any path which exits this function must decrement each of these metrics
240- // by the number of messages still waiting in this client's queue,
241- // or else they will grow without bound as clients disconnect, and be useless.
242- let incoming_queue_length_metric = WORKER_METRICS . total_incoming_queue_length . with_label_values ( & addr) ;
243- let outgoing_queue_length_metric = WORKER_METRICS . total_outgoing_queue_length . with_label_values ( & addr) ;
244-
245- let clean_up_metrics = |message_queue : & VecDeque < ( DataMessage , Instant ) > ,
246- sendrx : & mpsc:: Receiver < SerializableMessage > | {
247- incoming_queue_length_metric. sub ( message_queue. len ( ) as _ ) ;
248- outgoing_queue_length_metric. sub ( sendrx. len ( ) as _ ) ;
249- } ;
250-
251236 let mut msg_buffer = SerializeBuffer :: new ( client. config ) ;
252237 loop {
253238 rx_buf. clear ( ) ;
@@ -257,7 +242,6 @@ async fn ws_client_actor_inner(
257242 }
258243 if let MaybeDone :: Gone = * current_message {
259244 if let Some ( ( message, timer) ) = message_queue. pop_front ( ) {
260- incoming_queue_length_metric. dec ( ) ;
261245 let client = client. clone ( ) ;
262246 let fut = async move { client. handle_message ( message, timer) . await } ;
263247 current_message. set ( MaybeDone :: Future ( fut) ) ;
@@ -286,15 +270,13 @@ async fn ws_client_actor_inner(
286270 }
287271 // the client sent us a close frame
288272 None => {
289- clean_up_metrics( & message_queue, & sendrx) ;
290273 break
291274 } ,
292275 } ,
293276
294277 // If we have an outgoing message to send, send it off.
295278 // No incoming `message` to handle, so `continue`.
296279 Some ( n) = sendrx. recv_many( & mut rx_buf, 32 ) . map( |n| ( n != 0 ) . then_some( n) ) => {
297- outgoing_queue_length_metric. sub( n as _) ;
298280 if closed {
299281 // TODO: this isn't great. when we receive a close request from the peer,
300282 // tungstenite doesn't let us send any new messages on the socket,
@@ -379,7 +361,6 @@ async fn ws_client_actor_inner(
379361 } else {
380362 // the client never responded to our ping; drop them without trying to send them a Close
381363 log:: warn!( "client {} timed out" , client. id) ;
382- clean_up_metrics( & message_queue, & sendrx) ;
383364 break ;
384365 }
385366 }
@@ -394,7 +375,6 @@ async fn ws_client_actor_inner(
394375 match message {
395376 Item :: Message ( ClientMessage :: Message ( message) ) => {
396377 let timer = Instant :: now ( ) ;
397- incoming_queue_length_metric. inc ( ) ;
398378 message_queue. push_back ( ( message, timer) )
399379 }
400380 Item :: HandleResult ( res) => {
0 commit comments