1
- use std:: collections:: VecDeque ;
2
1
use std:: mem;
3
2
use std:: pin:: { pin, Pin } ;
4
3
use std:: time:: Duration ;
@@ -15,7 +14,10 @@ use http::{HeaderValue, StatusCode};
15
14
use scopeguard:: ScopeGuard ;
16
15
use serde:: Deserialize ;
17
16
use 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
+ } ;
19
21
use spacetimedb:: execution_context:: WorkloadType ;
20
22
use spacetimedb:: host:: module_host:: ClientConnectedError ;
21
23
use spacetimedb:: host:: NoSuchModule ;
@@ -25,7 +27,6 @@ use spacetimedb::Identity;
25
27
use spacetimedb_client_api_messages:: websocket:: { self as ws_api, Compression } ;
26
28
use spacetimedb_lib:: connection_id:: { ConnectionId , ConnectionIdForUrl } ;
27
29
use std:: time:: Instant ;
28
- use tokio:: sync:: mpsc;
29
30
use tokio_tungstenite:: tungstenite:: Utf8Bytes ;
30
31
31
32
use crate :: auth:: SpacetimeAuth ;
@@ -182,7 +183,7 @@ where
182
183
183
184
const LIVELINESS_TIMEOUT : Duration = Duration :: from_secs ( 60 ) ;
184
185
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 > ) {
186
187
// ensure that even if this task gets cancelled, we always cleanup the connection
187
188
let mut client = scopeguard:: guard ( client, |client| {
188
189
tokio:: spawn ( client. disconnect ( ) ) ;
@@ -204,11 +205,13 @@ async fn make_progress<Fut: Future>(fut: &mut Pin<&mut MaybeDone<Fut>>) {
204
205
async fn ws_client_actor_inner (
205
206
client : & mut ClientConnection ,
206
207
mut ws : WebSocketStream ,
207
- mut sendrx : mpsc :: Receiver < SerializableMessage > ,
208
+ mut sendrx : MeteredReceiver < SerializableMessage > ,
208
209
) {
209
210
let mut liveness_check_interval = tokio:: time:: interval ( LIVELINESS_TIMEOUT ) ;
210
211
let mut got_pong = true ;
211
212
213
+ let addr = client. module . info ( ) . database_identity ;
214
+
212
215
// Build a queue of incoming messages to handle, to be processed one at a time,
213
216
// in the order they're received.
214
217
//
@@ -222,32 +225,14 @@ async fn ws_client_actor_inner(
222
225
// `select!` for examples of how to do this.
223
226
//
224
227
// 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
+ ) ;
226
231
let mut current_message = pin ! ( MaybeDone :: Gone ) ;
227
232
228
233
let mut closed = false ;
229
234
let mut rx_buf = Vec :: new ( ) ;
230
235
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
-
251
236
let mut msg_buffer = SerializeBuffer :: new ( client. config ) ;
252
237
loop {
253
238
rx_buf. clear ( ) ;
@@ -257,7 +242,6 @@ async fn ws_client_actor_inner(
257
242
}
258
243
if let MaybeDone :: Gone = * current_message {
259
244
if let Some ( ( message, timer) ) = message_queue. pop_front ( ) {
260
- incoming_queue_length_metric. dec ( ) ;
261
245
let client = client. clone ( ) ;
262
246
let fut = async move { client. handle_message ( message, timer) . await } ;
263
247
current_message. set ( MaybeDone :: Future ( fut) ) ;
@@ -286,15 +270,13 @@ async fn ws_client_actor_inner(
286
270
}
287
271
// the client sent us a close frame
288
272
None => {
289
- clean_up_metrics( & message_queue, & sendrx) ;
290
273
break
291
274
} ,
292
275
} ,
293
276
294
277
// If we have an outgoing message to send, send it off.
295
278
// No incoming `message` to handle, so `continue`.
296
279
Some ( n) = sendrx. recv_many( & mut rx_buf, 32 ) . map( |n| ( n != 0 ) . then_some( n) ) => {
297
- outgoing_queue_length_metric. sub( n as _) ;
298
280
if closed {
299
281
// TODO: this isn't great. when we receive a close request from the peer,
300
282
// tungstenite doesn't let us send any new messages on the socket,
@@ -379,7 +361,6 @@ async fn ws_client_actor_inner(
379
361
} else {
380
362
// the client never responded to our ping; drop them without trying to send them a Close
381
363
log:: warn!( "client {} timed out" , client. id) ;
382
- clean_up_metrics( & message_queue, & sendrx) ;
383
364
break ;
384
365
}
385
366
}
@@ -394,7 +375,6 @@ async fn ws_client_actor_inner(
394
375
match message {
395
376
Item :: Message ( ClientMessage :: Message ( message) ) => {
396
377
let timer = Instant :: now ( ) ;
397
- incoming_queue_length_metric. inc ( ) ;
398
378
message_queue. push_back ( ( message, timer) )
399
379
}
400
380
Item :: HandleResult ( res) => {
0 commit comments