Skip to content

Commit 5b3ea19

Browse files
GnomedDevarqunis
andauthored
Fix out of order cache updates (#3342)
Co-authored-by: Alex M. M. <[email protected]>
1 parent 243c5b2 commit 5b3ea19

File tree

3 files changed

+34
-37
lines changed

3 files changed

+34
-37
lines changed

src/gateway/client/dispatch.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::cache::{Cache, CacheUpdate};
77
#[cfg(feature = "framework")]
88
use crate::framework::Framework;
99
use crate::internal::prelude::*;
10+
use crate::internal::tokio::spawn_named;
1011
use crate::model::channel::ChannelType;
1112
use crate::model::event::Event;
1213
use crate::model::guild::Member;
@@ -40,9 +41,6 @@ macro_rules! update_cache {
4041
}
4142

4243
/// Calls the user's event handlers and the framework handler.
43-
///
44-
/// This MUST be called from a different task to the recv_event loop, to allow for
45-
/// intra-shard concurrency between the shard loop and event handler.
4644
pub(crate) async fn dispatch_model(
4745
event: Box<Event>,
4846
context: Context,
@@ -60,14 +58,16 @@ pub(crate) async fn dispatch_model(
6058
event,
6159
);
6260

63-
#[cfg(feature = "framework")]
64-
tokio::join!(
65-
dispatch_framework(&context, framework, &full_event, extra_event.as_ref()),
66-
dispatch_event_handler(&context, event_handler, &full_event, extra_event.as_ref())
67-
);
61+
spawn_named("dispatch::user", async move {
62+
#[cfg(feature = "framework")]
63+
tokio::join!(
64+
dispatch_framework(&context, framework, &full_event, extra_event.as_ref()),
65+
dispatch_event_handler(&context, event_handler, &full_event, extra_event.as_ref())
66+
);
6867

69-
#[cfg(not(feature = "framework"))]
70-
dispatch_event_handler(&context, event_handler, &full_event, extra_event.as_ref()).await;
68+
#[cfg(not(feature = "framework"))]
69+
dispatch_event_handler(&context, event_handler, &full_event, extra_event.as_ref()).await;
70+
});
7171
}
7272

7373
#[cfg(feature = "framework")]

src/gateway/client/event_handler.rs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use async_trait::async_trait;
66
use strum::{EnumCount, IntoStaticStr, VariantNames};
77

88
use super::context::Context;
9+
#[cfg(doc)]
10+
use crate::gateway::ShardRunner;
911
use crate::gateway::ShardStageUpdateEvent;
1012
use crate::http::RatelimitInfo;
1113
use crate::model::prelude::*;
@@ -19,12 +21,8 @@ pub trait EventHandler: Send + Sync {
1921
///
2022
/// ## Warning
2123
///
22-
/// This will run synchronously on every event in the dispatch loop
23-
/// of the shard that is receiving the event. If your filter code
24-
/// takes too long, it may delay other events from being dispatched
25-
/// in a timely manner. It is recommended to keep the runtime
26-
/// complexity of the filter code low to avoid unnecessarily blocking
27-
/// your bot.
24+
/// Similar to [`RawEventHandler`], this method runs synchronously to the [`ShardRunner`], keep
25+
/// runtime complexity low.
2826
fn filter_event(&self, _context: &Context, _event: &Event) -> bool {
2927
true
3028
}
@@ -415,7 +413,17 @@ full_event! {
415413
MessagePollVoteRemove { event: MessagePollVoteRemoveEvent };
416414
}
417415

418-
/// This core trait for handling raw events
416+
/// An event handler that receives raw `dispatch` events.
417+
///
418+
/// ## Warning
419+
/// As this is a low level trait, the methods of this trait are run on the same tokio task as the
420+
/// [`ShardRunner`].
421+
///
422+
/// This means that if any of these methods take too long to return, the shard may drop events or be
423+
/// disconnected entirely.
424+
///
425+
/// It is recommended to clone the fields needed out of [`Event`], then spawn a task to run
426+
/// concurrently to the shard loop.
419427
#[async_trait]
420428
pub trait RawEventHandler: Send + Sync {
421429
/// Dispatched when any event occurs
@@ -425,15 +433,6 @@ pub trait RawEventHandler: Send + Sync {
425433
///
426434
/// Returning `false` will drop an event and prevent it being dispatched by any frameworks and
427435
/// will exclude it from any collectors.
428-
///
429-
/// ## Warning
430-
///
431-
/// This will run synchronously on every event in the dispatch loop
432-
/// of the shard that is receiving the event. If your filter code
433-
/// takes too long, it may delay other events from being dispatched
434-
/// in a timely manner. It is recommended to keep the runtime
435-
/// complexity of the filter code low to avoid unnecessarily blocking
436-
/// your bot.
437436
fn filter_event(&self, _context: &Context, _event: &Event) -> bool {
438437
// Suppress unused argument warnings
439438
true

src/gateway/sharding/shard_runner.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -214,17 +214,15 @@ impl ShardRunner {
214214
#[cfg(feature = "collector")]
215215
self.collectors.write().retain(|callback| (callback.0)(&event));
216216

217-
spawn_named(
218-
"shard_runner::dispatch",
219-
dispatch_model(
220-
event,
221-
context,
222-
#[cfg(feature = "framework")]
223-
self.framework.clone(),
224-
self.event_handler.clone(),
225-
self.raw_event_handler.clone(),
226-
),
227-
);
217+
dispatch_model(
218+
event,
219+
context,
220+
#[cfg(feature = "framework")]
221+
self.framework.clone(),
222+
self.event_handler.clone(),
223+
self.raw_event_handler.clone(),
224+
)
225+
.await;
228226
}
229227
},
230228
}

0 commit comments

Comments
 (0)