Skip to content

Commit 9fe46cb

Browse files
committed
spread out debouce times per-connection
Signed-off-by: Robin Appelman <robin@icewind.nl>
1 parent 278f92f commit 9fe46cb

2 files changed

Lines changed: 33 additions & 17 deletions

File tree

src/connection.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{App, UserId};
1212
use dashmap::mapref::entry::Entry;
1313
use dashmap::DashMap;
1414
use futures::{future::select, pin_mut, SinkExt, StreamExt};
15-
use rand::{Rng, SeedableRng};
15+
use rand::{thread_rng, Rng, SeedableRng};
1616
use std::net::IpAddr;
1717
use std::num::NonZeroUsize;
1818
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
@@ -131,11 +131,15 @@ pub async fn handle_user_socket(
131131
let expect_pong = &expect_pong;
132132

133133
let transmit = async {
134-
// Use faster random generator for generating ping messages, they dont need to be
135-
// cryptographically secure. It is also OK to use same sequence for every connection.
136-
let mut rng = rand::rngs::SmallRng::seed_from_u64(0);
134+
// Use faster random generator for generating ping messages and time smearthey dont need to be
135+
// cryptographically secure.
136+
let mut rng =
137+
rand::rngs::SmallRng::from_rng(thread_rng()).expect("Failed to initialize rng");
137138

138-
let mut send_queue = SendQueue::new(opts.max_debounce_time);
139+
// for each connection we randomize the max debounce time to remove the chance that many connections
140+
// get messages at the same time and cause load peaks
141+
let debounce_factor = rng.gen_range(0.5..1.5);
142+
let mut send_queue = SendQueue::new(opts.max_debounce_time, debounce_factor);
139143

140144
let mut reset = app.reset_rx();
141145

src/message.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,21 @@ impl PushMessage {
5959
}
6060
}
6161

62-
pub fn debounce_time(&self, connection_count: usize, max_debounce_time: usize) -> Duration {
62+
pub fn debounce_time(
63+
&self,
64+
connection_count: usize,
65+
max_debounce_time: usize,
66+
debounce_factor: f32,
67+
) -> Duration {
6368
// scale the debounce time between 1s and 15s based on the number of active connections
64-
// this provide a decent balance between performance and load
65-
let time = max(1, min(connection_count / 10, max_debounce_time));
69+
// this provides a decent balance between performance and load.
70+
// Additionally, each connection will have a random debounce_factor between 0.5 and 1.5
71+
// to spread out the load of notifications.
72+
let time = max(1, min(connection_count / 10, max_debounce_time)) as f32;
73+
let time = time * debounce_factor;
6674
match self {
67-
PushMessage::File(_) => Duration::from_secs(time as u64),
68-
PushMessage::Activity => Duration::from_secs(time as u64),
75+
PushMessage::File(_) => Duration::from_secs_f32(time),
76+
PushMessage::Activity => Duration::from_secs_f32(time),
6977
PushMessage::Notification => Duration::from_secs(1),
7078
PushMessage::Custom(..) => Duration::from_millis(1), // no debouncing for custom messages
7179
}
@@ -138,13 +146,15 @@ impl Default for SendQueueItem {
138146
#[derive(Debug)]
139147
pub struct SendQueue {
140148
max_debounce_time: usize,
149+
debounce_factor: f32,
141150
items: [SendQueueItem; 3],
142151
}
143152

144153
impl SendQueue {
145-
pub fn new(max_debounce_time: usize) -> Self {
154+
pub fn new(max_debounce_time: usize, debounce_factor: f32) -> Self {
146155
SendQueue {
147156
max_debounce_time,
157+
debounce_factor,
148158
items: Default::default(),
149159
}
150160
}
@@ -186,11 +196,13 @@ impl SendQueue {
186196
connection_count: usize,
187197
) -> impl Iterator<Item = PushMessage> + '_ {
188198
let max_debounce_time = self.max_debounce_time;
199+
let debounce_factor = self.debounce_factor;
189200
self.items.iter_mut().filter_map(move |item| {
190-
let debounce_time = item
191-
.message
192-
.as_ref()?
193-
.debounce_time(connection_count, max_debounce_time);
201+
let debounce_time = item.message.as_ref()?.debounce_time(
202+
connection_count,
203+
max_debounce_time,
204+
debounce_factor,
205+
);
194206
if now.duration_since(item.sent) > debounce_time {
195207
if now.duration_since(item.received) > Duration::from_millis(100) {
196208
item.sent = now;
@@ -208,7 +220,7 @@ impl SendQueue {
208220
#[test]
209221
fn test_send_queue_100() {
210222
let base_time = Instant::now();
211-
let mut queue = SendQueue::new(15);
223+
let mut queue = SendQueue::new(15, 1.0);
212224
queue.push(PushMessage::Activity, base_time);
213225
queue.push(
214226
PushMessage::File(UpdatedFiles::Known(vec![1].into())),
@@ -274,7 +286,7 @@ fn test_send_queue_100() {
274286
#[test]
275287
fn test_send_queue_1() {
276288
let base_time = Instant::now();
277-
let mut queue = SendQueue::new(15);
289+
let mut queue = SendQueue::new(15, 1.0);
278290
queue.push(PushMessage::Activity, base_time);
279291
queue.push(
280292
PushMessage::File(UpdatedFiles::Known(vec![1].into())),

0 commit comments

Comments
 (0)