Skip to content

Commit adf1268

Browse files
committed
relax exact gateway session resume count match
Requring an exact match causes unexpected invalidations. At least 25% more guilds are supported in the worst case.
1 parent 651e7c7 commit adf1268

File tree

2 files changed

+33
-31
lines changed

2 files changed

+33
-31
lines changed

src/main.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,6 @@ async fn main() -> anyhow::Result<()> {
3838
let info = async { Ok::<_, anyhow::Error>(http.gateway().authed().await?.model().await?) }
3939
.await
4040
.context("getting info")?;
41-
async {
42-
http.interaction(APPLICATION_ID)
43-
.set_global_commands(&command::global_commands())
44-
.await?;
45-
http.interaction(APPLICATION_ID)
46-
.set_guild_commands(ADMIN_GUILD_ID, &command::admin_commands(info.shards))
47-
.await?;
48-
Ok::<_, anyhow::Error>(())
49-
}
50-
.await
51-
.context("putting commands")?;
52-
let shard_handles = DashMap::new();
53-
context::initialize(http, shard_handles);
5441

5542
// The queue defaults are static and may be incorrect for large or newly
5643
// restarted bots.
@@ -61,9 +48,25 @@ async fn main() -> anyhow::Result<()> {
6148
info.session_start_limit.total,
6249
);
6350
let config = ConfigBuilder::new(token, INTENTS).queue(queue).build();
64-
6551
let shards = resume::restore(config, info.shards).await;
6652

53+
async {
54+
http.interaction(APPLICATION_ID)
55+
.set_global_commands(&command::global_commands())
56+
.await?;
57+
http.interaction(APPLICATION_ID)
58+
.set_guild_commands(
59+
ADMIN_GUILD_ID,
60+
&command::admin_commands(shards.len() as u32),
61+
)
62+
.await?;
63+
Ok::<_, anyhow::Error>(())
64+
}
65+
.await
66+
.context("putting commands")?;
67+
let shard_handles = DashMap::with_capacity(shards.len());
68+
context::initialize(http, shard_handles);
69+
6770
let tasks = shards
6871
.into_iter()
6972
.map(|shard| tokio::spawn(dispatch::run(shard, event_handler)))

src/resume.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use serde::{Deserialize, Serialize};
2+
use std::iter;
23
use tokio::fs;
34
use twilight_gateway::{Config, ConfigBuilder, Session, Shard, ShardId};
45

@@ -54,37 +55,35 @@ pub async fn save(info: &[Info]) -> anyhow::Result<()> {
5455
}
5556

5657
/// Restores shard resumption information from the file system.
57-
pub async fn restore(config: Config, shards: u32) -> Vec<Shard> {
58+
pub async fn restore(config: Config, recommended_shards: u32) -> Vec<Shard> {
5859
let info = async {
5960
let contents = fs::read(INFO_FILE).await?;
6061
Ok::<_, anyhow::Error>(serde_json::from_slice::<Vec<Info>>(&contents)?)
6162
}
6263
.await;
6364

64-
let shard_ids = (0..shards).map(|shard| ShardId::new(shard, shards));
65-
66-
// A session may only be successfully resumed if it retains its shard ID, but
67-
// Discord may have recommend a different shard count (producing different shard
68-
// IDs).
69-
let shards: Vec<_> = if let Ok(info) = info
70-
&& info.len() == shards as usize
65+
// The recommended shard count targets 1000 guilds per shard (out of a maximum
66+
// of 2500), so it might be different from the previous shard count.
67+
let shards = if let Ok(info) = info
68+
&& recommended_shards / 2 <= info.len() as u32
7169
{
7270
tracing::info!("resuming previous gateway sessions");
73-
shard_ids
71+
let configs = iter::repeat_n(config, info.len())
7472
.zip(info)
75-
.map(|(shard_id, info)| {
76-
let builder = ConfigBuilder::from(config.clone()).resume_info(info);
77-
Shard::with_config(shard_id, builder.build())
78-
})
79-
.collect()
73+
.map(|(config, info)| ConfigBuilder::from(config).resume_info(info).build());
74+
shards(configs).collect()
8075
} else {
81-
shard_ids
82-
.map(|shard_id| Shard::with_config(shard_id, config.clone()))
83-
.collect()
76+
shards(iter::repeat_n(config, recommended_shards as usize)).collect()
8477
};
8578

8679
// Resumed or not, the saved resume info is now stale.
8780
_ = fs::remove_file(INFO_FILE).await;
8881

8982
shards
9083
}
84+
85+
fn shards(iter: impl ExactSizeIterator<Item = Config>) -> impl ExactSizeIterator<Item = Shard> {
86+
let total = iter.len() as u32;
87+
iter.zip((0..total).map(move |id| ShardId::new(id, total)))
88+
.map(|(config, shard_id)| Shard::with_config(shard_id, config))
89+
}

0 commit comments

Comments
 (0)