-
-
Notifications
You must be signed in to change notification settings - Fork 266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[3.2.x] ConnectEvent not triggered if not first event subscribed to (Default EventDispatcher was changed from 3.1.8) (regression?) #1159
Comments
The "ConnectEvent" (as well as the ReadyEvent) is dispatched when a connection is established to the gateway. It it called during the ".login().block()" part, before your listeners are registered. To run some code when your bot is started, you have two options:
DiscordClientBuilder.create("<token>")
.build()
.gateway()
.setEnabledIntents(IntentSet.all())
.withGateway(gatewayDiscordClient -> {
gatewayDiscordClient.on(ReadyEvent.class).subscribe(interactionCreateEvent -> {
logger.info("ReadyEvent!");
});
return gatewayDiscordClient.onDisconnect();
})
.block();
|
Be aware that using the 1st method will completly block the thread, as the provided code is equivalent to calling |
Is this some kind of race condition then ? |
Anyway 1. is a good way to avoid undefined behaviour then ! Thanks ! |
Nope, the "issue" is using .gateway(). This code works without any issue in 3.2.6-SNAPSHOT: var client = DiscordClientBuilder.create("<token>")
.build()
.login().block();
client.on(ReadyEvent.class).subscribe(readyEvent -> {
logger.info("ReadyEvent!");
}); If you want to use both the gateway (to enable intents) and the event, you should use the method 1. I provided early. |
This is 100% a behaviour change introduced by the .gateway() method. We should add a warning in the docs and examples for the newcomers 😅 |
Ohhh I see, I did not notice the repro code I used for 3.1.8 did not have .gateway() ... This is even weirder then 🤔
client = DiscordClientBuilder.create(config.discord_token).build();
gateway = client.login().block();
Thread.sleep(100000);
gateway.getEventDispatcher().on(ConnectEvent.class).subscribe(event -> { System.out.println("Connect called"); });
gateway.getEventDispatcher().on(VoiceStateUpdateEvent.class).subscribe(event -> { System.out.println("Voice state called"); }); |
Hilariously enough client = DiscordClientBuilder.create(config.discord_token).build();
gateway = client.gateway().setEnabledIntents(IntentSet.all()).login().block();
Thread.sleep(100000);
gateway.getEventDispatcher().on(ConnectEvent.class).subscribe(event -> { System.out.println("Connect called"); });
gateway.getEventDispatcher().on(VoiceStateUpdateEvent.class).subscribe(event -> { System.out.println("Voice state called"); }); Works perfectly on 3.2.5 so we can rule out race condition I guess. |
And in your case, as your "first subscription" is not listening for "startup events", they will be dismissed |
(And that also explains why adding a Thread.sleep make the event still appears) |
Seems like it. However client = DiscordClientBuilder.create(config.discord_token).build();
gateway = client.login().block();
Thread.sleep(100000);
gateway.getEventDispatcher().on(VoiceStateUpdateEvent.class).subscribe(event -> { System.out.println("Voice state called"); });
gateway.getEventDispatcher().on(ConnectEvent.class).subscribe(event -> { System.out.println("Connect called"); }); (i.e. without using .gateway()) Works on 2.1.8 but not on 2.2.5. |
Yup, that's intended, the default eventDispatcher only dispatches startup events to the first subscription made. In your case that's a listen for "VoiceStateUpdateEvent", so all the startup event saved will be dropped |
To adress this issue, you have three options then:
|
Yep
Weird then, it means the default event dispatcher got changed without obvious reasons and without being documented in the migration guide ? (Tho I guess this may be too specific to make it to the migration guide)
Yup, good to have found the root issue, the Would be interesting to dig why the default even dispatcher got changed in the first place tho. Would be good to know if it is a fluke or if there is an underlying issue with replaying... |
By "intended" I mean that the documentation (javadoc) correspond to the behaviour we experience, there is no bug here. 👋 @quanticc if you have any idea why this changed, you know better than me 😅 (I ping you specifically bc you seems to be more active than the other core team members, sorry if I shouldn't have) |
Found it : private EventDispatcher initEventDispatcher(ReactorResources reactorResources) {
if (eventDispatcher != null) {
return eventDispatcher;
}
return ReplayingEventDispatcher.builder()
.timedTaskScheduler(reactorResources.getTimerTaskScheduler())
.build();
} In private EventDispatcher initEventDispatcher() {
if (eventDispatcher != null) {
return eventDispatcher;
}
return EventDispatcher.buffering();
} In |
Seems kinda weird Then as of December 25 2019 it got changed to buffered As of June 12 2020, buffered got changed to replaying in 2.1.x (current 2.1.8) Then on November 22 2020 it got reverted to buffered but only in 2.2.x (current 2.2.5) (all by quanticc so I guess you pinged the right person :) ) |
Thanks for bringing this up, from what I can remember to explain the weirdness: In Discord4J 3.0, sharding/login process was done differently:
This meant you could register all listeners before a websocket is opened using Since our event dispatchers use EmitterProcessor under the hood:
However, when we introduced Discord4J 3.1,
Registering listeners using To keep supporting old 2.x/3.0 behavior as much as possible,
The result depended on API that Reactor announced it will deprecate in a future release: there's less incentive to support ReplayingEventDispatcher going forward. Therefore it didn't become the default option in v3.2, because We also introduced Definitely an issue on our end lacking docs about event listening methods, I hope for now this can clear the confusion. |
Event ConnectEvent is never called if not the first event subcribed to.
I spend all day figuring it out and I can find nothing about it in the docs or anywhere else.
Can confirm it worked for sure before, as I've been updating an old bot. At minimum 3.1.8 worked as intended.
EDIT: tested all versions from 3.2.0 to 3.2.5 and none of them work as intended.
EDIT: I can confirm 3.1.8 works as intended (see code in other).
To Reproduce:
Note: example use
VoiceStateUpdateEvent
but any event do (Tested withChatInputInteractionEvent
,VoiceStateUpdateEvent
andDisconnectEvent
).Note: the other event is always called as expected whatever the order.
Note:
ReconnectEvent
is called as expected.Expected Behavior:
OnConnectEvent is called
Actual Behavior:
OnConnectEvent never called
Version:
Discord4j 3.2.0 -> 3.2.5
Other:
Workaround, subscribe ConnectEvent first :
EDIT: test code for 3.1.8
The text was updated successfully, but these errors were encountered: