Skip to content

Commit 46c6311

Browse files
cheesycodGnomedDev
andauthored
Add config for the shard start wait time (#3031)
Co-authored-by: Gnome! <[email protected]>
1 parent dba4fa6 commit 46c6311

File tree

4 files changed

+46
-12
lines changed

4 files changed

+46
-12
lines changed

src/gateway/client/mod.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use std::ops::Range;
3333
use std::sync::Arc;
3434
#[cfg(feature = "framework")]
3535
use std::sync::OnceLock;
36+
use std::time::Duration;
3637

3738
use futures::channel::mpsc::UnboundedReceiver as Receiver;
3839
use futures::future::BoxFuture;
@@ -49,7 +50,14 @@ use crate::cache::Settings as CacheSettings;
4950
use crate::framework::Framework;
5051
#[cfg(feature = "voice")]
5152
use crate::gateway::VoiceGatewayManager;
52-
use crate::gateway::{ActivityData, GatewayError, PresenceData, ShardManager, ShardManagerOptions};
53+
use crate::gateway::{
54+
ActivityData,
55+
GatewayError,
56+
PresenceData,
57+
ShardManager,
58+
ShardManagerOptions,
59+
DEFAULT_WAIT_BETWEEN_SHARD_START,
60+
};
5361
use crate::http::Http;
5462
use crate::internal::prelude::*;
5563
use crate::internal::tokio::spawn_named;
@@ -73,6 +81,7 @@ pub struct ClientBuilder {
7381
event_handler: Option<Arc<dyn EventHandler>>,
7482
raw_event_handler: Option<Arc<dyn RawEventHandler>>,
7583
presence: PresenceData,
84+
wait_time_between_shard_start: Duration,
7685
}
7786

7887
impl ClientBuilder {
@@ -106,6 +115,7 @@ impl ClientBuilder {
106115
event_handler: None,
107116
raw_event_handler: None,
108117
presence: PresenceData::default(),
118+
wait_time_between_shard_start: DEFAULT_WAIT_BETWEEN_SHARD_START,
109119
}
110120
}
111121

@@ -153,6 +163,19 @@ impl ClientBuilder {
153163
self.framework.as_deref()
154164
}
155165

166+
/// Sets the time to wait between starting shards.
167+
///
168+
/// This should only be used when using a gateway proxy, such as [Sandwich] or [Twilight Gateway
169+
/// Proxy], as otherwise this will lead to gateway disconnects if the shard start rate limit is
170+
/// not respected.
171+
///
172+
/// [Sandwich]: https://github.com/WelcomerTeam/Sandwich-Daemon
173+
/// [Twilight Gateway Proxy]: https://github.com/Gelbpunkt/gateway-proxy
174+
pub fn wait_time_between_shard_start(mut self, wait_time: Duration) -> Self {
175+
self.wait_time_between_shard_start = wait_time;
176+
self
177+
}
178+
156179
/// Sets the voice gateway handler to be used. It will receive voice events sent over the
157180
/// gateway and then consider - based on its settings - whether to dispatch a command.
158181
#[cfg(feature = "voice")]
@@ -318,6 +341,7 @@ impl IntoFuture for ClientBuilder {
318341
intents,
319342
presence: Some(presence),
320343
max_concurrency,
344+
wait_time_between_shard_start: self.wait_time_between_shard_start,
321345
});
322346

323347
let client = Client {

src/gateway/sharding/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ use tokio_tungstenite::tungstenite::protocol::frame::CloseFrame;
5050
use tracing::{debug, error, info, trace, warn};
5151
use url::Url;
5252

53-
pub use self::shard_manager::{ShardManager, ShardManagerOptions};
53+
pub use self::shard_manager::{
54+
ShardManager,
55+
ShardManagerOptions,
56+
DEFAULT_WAIT_BETWEEN_SHARD_START,
57+
};
5458
pub use self::shard_messenger::ShardMessenger;
5559
pub use self::shard_queuer::{ShardQueue, ShardQueuer, ShardQueuerMessage};
5660
pub use self::shard_runner::{ShardRunner, ShardRunnerMessage, ShardRunnerOptions};

src/gateway/sharding/shard_manager.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ use crate::internal::prelude::*;
2525
use crate::internal::tokio::spawn_named;
2626
use crate::model::gateway::GatewayIntents;
2727

28+
/// The default time to wait between starting each shard or set of shards.
29+
pub const DEFAULT_WAIT_BETWEEN_SHARD_START: Duration = Duration::from_secs(5);
30+
2831
/// A manager for handling the status of shards by starting them, restarting them, and stopping
2932
/// them when required.
3033
///
@@ -50,7 +53,7 @@ use crate::model::gateway::GatewayIntents;
5053
/// use std::sync::{Arc, OnceLock};
5154
///
5255
/// use serenity::gateway::client::EventHandler;
53-
/// use serenity::gateway::{ShardManager, ShardManagerOptions};
56+
/// use serenity::gateway::{ShardManager, ShardManagerOptions, DEFAULT_WAIT_BETWEEN_SHARD_START};
5457
/// use serenity::http::Http;
5558
/// use serenity::model::gateway::GatewayIntents;
5659
/// use serenity::prelude::*;
@@ -84,6 +87,7 @@ use crate::model::gateway::GatewayIntents;
8487
/// intents: GatewayIntents::non_privileged(),
8588
/// presence: None,
8689
/// max_concurrency,
90+
/// wait_time_between_shard_start: DEFAULT_WAIT_BETWEEN_SHARD_START,
8791
/// });
8892
/// # Ok(())
8993
/// # }
@@ -146,6 +150,7 @@ impl ShardManager {
146150
http: opt.http,
147151
intents: opt.intents,
148152
presence: opt.presence,
153+
wait_time_between_shard_start: opt.wait_time_between_shard_start,
149154
};
150155

151156
spawn_named("shard_queuer::run", async move {
@@ -372,4 +377,6 @@ pub struct ShardManagerOptions {
372377
pub intents: GatewayIntents,
373378
pub presence: Option<PresenceData>,
374379
pub max_concurrency: NonZeroU16,
380+
/// Number of seconds to wait between starting each shard/set of shards start
381+
pub wait_time_between_shard_start: Duration,
375382
}

src/gateway/sharding/shard_queuer.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ use crate::internal::prelude::*;
3131
use crate::internal::tokio::spawn_named;
3232
use crate::model::gateway::{GatewayIntents, ShardInfo};
3333

34-
const WAIT_BETWEEN_BOOTS_IN_SECONDS: u64 = 5;
35-
3634
/// The shard queuer is a simple loop that runs indefinitely to manage the startup of shards.
3735
///
3836
/// A shard queuer instance _should_ be run in its own thread, due to the blocking nature of the
@@ -68,6 +66,8 @@ pub struct ShardQueuer {
6866
pub ws_url: Arc<str>,
6967
/// The total amount of shards to start.
7068
pub shard_total: NonZeroU16,
69+
/// Number of seconds to wait between each start
70+
pub wait_time_between_shard_start: Duration,
7171
#[cfg(feature = "cache")]
7272
pub cache: Arc<Cache>,
7373
pub http: Arc<Http>,
@@ -94,14 +94,14 @@ impl ShardQueuer {
9494
/// **Note**: This should be run in its own thread due to the blocking nature of the loop.
9595
#[cfg_attr(feature = "tracing_instrument", instrument(skip(self)))]
9696
pub async fn run(&mut self) {
97-
// We read from the Rx channel in a loop, and use a timeout of 5 seconds so that we don't
97+
// We read from the Rx channel in a loop, and use a timeout of
98+
// {self.WAIT_TIME_BETWEEN_SHARD_START} (5 seconds normally) seconds so that we don't
9899
// hang forever. When we receive a command to start a shard, we append it to our queue. The
99100
// queue is popped in batches of shards, which are started in parallel. A batch is fired
100-
// every 5 seconds at minimum in order to avoid being ratelimited.
101-
const TIMEOUT: Duration = Duration::from_secs(WAIT_BETWEEN_BOOTS_IN_SECONDS);
101+
// every WAIT_TIME_BETWEEN_SHARD_START at minimum in order to avoid being ratelimited.
102102

103103
loop {
104-
if let Ok(msg) = timeout(TIMEOUT, self.rx.next()).await {
104+
if let Ok(msg) = timeout(self.wait_time_between_shard_start, self.rx.next()).await {
105105
match msg {
106106
Some(ShardQueuerMessage::SetShardTotal(shard_total)) => {
107107
self.shard_total = shard_total;
@@ -157,14 +157,13 @@ impl ShardQueuer {
157157
let Some(instant) = self.last_start else { return };
158158

159159
// We must wait 5 seconds between IDENTIFYs to avoid session invalidations.
160-
let duration = Duration::from_secs(WAIT_BETWEEN_BOOTS_IN_SECONDS);
161160
let elapsed = instant.elapsed();
162161

163-
if elapsed >= duration {
162+
if elapsed >= self.wait_time_between_shard_start {
164163
return;
165164
}
166165

167-
let to_sleep = duration - elapsed;
166+
let to_sleep = self.wait_time_between_shard_start - elapsed;
168167

169168
sleep(to_sleep).await;
170169
}

0 commit comments

Comments
 (0)