From b44e559ad3e66503e9752a6d60e450fb3c52f22b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 22:01:51 +0000 Subject: [PATCH] fix: make network requests asynchronous Refactored the Heartbeat, TipChatter, and UserOnLogin classes to use Velocity's asynchronous scheduler. This moves all blocking network requests off the main server thread, which will prevent them from causing performance issues and disconnects. --- .../zander/velocity/ZanderVelocityMain.java | 3 ++ .../velocity/events/session/UserOnLogin.java | 54 +++++++++---------- .../util/announcement/TipChatter.java | 15 ++---- .../zander/velocity/util/api/Heartbeat.java | 12 ++--- 4 files changed, 36 insertions(+), 48 deletions(-) diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java index 15a42c3..bb6ab02 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/ZanderVelocityMain.java @@ -53,6 +53,8 @@ public class ZanderVelocityMain { private static YamlDocument config; @Getter private final CommandManager commandManager; + @Getter + private static ZanderVelocityMain instance; @Subscribe public void onProxyInitialization(ProxyInitializeEvent event) { @@ -94,6 +96,7 @@ public ZanderVelocityMain( this.proxy = proxy; this.logger = logger; this.commandManager = commandManager; + instance = this; // Create configuration file try { diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnLogin.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnLogin.java index 6eea4a9..b150afa 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnLogin.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/events/session/UserOnLogin.java @@ -6,8 +6,6 @@ import dev.dejvokep.boostedyaml.route.Route; import io.github.ModularEnigma.Request; import io.github.ModularEnigma.Response; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; import org.modularsoft.zander.velocity.ZanderVelocityMain; import org.modularsoft.zander.velocity.model.discord.DiscordJoin; import org.modularsoft.zander.velocity.model.session.SessionCreate; @@ -17,29 +15,30 @@ public class UserOnLogin { @Subscribe public void UserLoginEvent (PostLoginEvent event) { Player player = event.getPlayer(); - String BaseAPIURL = ZanderVelocityMain.getConfig().getString(Route.from("BaseAPIURL")); - String APIKey = ZanderVelocityMain.getConfig().getString(Route.from("APIKey")); - try { - // - // Send User Creation API POST for new user - // - UserCreation createUser = UserCreation.builder() - .uuid(player.getUniqueId()) - .username(player.getUsername()) - .build(); + ZanderVelocityMain.getProxy().getScheduler().buildTask(ZanderVelocityMain.getInstance(), () -> { + String BaseAPIURL = ZanderVelocityMain.getConfig().getString(Route.from("BaseAPIURL")); + String APIKey = ZanderVelocityMain.getConfig().getString(Route.from("APIKey")); - Request createUserReq = Request.builder() - .setURL(BaseAPIURL + "/user/create") - .setMethod(Request.Method.POST) - .addHeader("x-access-token", APIKey) - .setRequestBody(createUser.toString()) - .build(); + try { + // + // Send User Creation API POST for new user + // + UserCreation createUser = UserCreation.builder() + .uuid(player.getUniqueId()) + .username(player.getUsername()) + .build(); - Response createUserRes = createUserReq.execute(); - ZanderVelocityMain.getLogger().info("Response (" + createUserRes.getStatusCode() + "): " + createUserRes.getBody()); + Request createUserReq = Request.builder() + .setURL(BaseAPIURL + "/user/create") + .setMethod(Request.Method.POST) + .addHeader("x-access-token", APIKey) + .setRequestBody(createUser.toString()) + .build(); + + Response createUserRes = createUserReq.execute(); + ZanderVelocityMain.getLogger().info("User creation response (" + createUserRes.getStatusCode() + "): " + createUserRes.getBody()); - try { // // Start Session API POST // @@ -56,7 +55,7 @@ public void UserLoginEvent (PostLoginEvent event) { .build(); Response createSessionRes = createSessionReq.execute(); - ZanderVelocityMain.getLogger().info("Response (" + createSessionRes.getStatusCode() + "): " + createSessionRes.getBody()); + ZanderVelocityMain.getLogger().info("Session creation response (" + createSessionRes.getStatusCode() + "): " + createSessionRes.getBody()); // Send Discord API POST for join message DiscordJoin join = DiscordJoin.builder() @@ -71,14 +70,11 @@ public void UserLoginEvent (PostLoginEvent event) { .build(); Response discordJoinRes = discordJoinReq.execute(); - ZanderVelocityMain.getLogger().info("Response (" + discordJoinRes.getStatusCode() + "): " + discordJoinRes.getBody()); + ZanderVelocityMain.getLogger().info("Discord join response (" + discordJoinRes.getStatusCode() + "): " + discordJoinRes.getBody()); + } catch (Exception e) { - Component builder = Component.text("An error has occurred. Is the API down?").color(NamedTextColor.RED); - player.disconnect(builder); + ZanderVelocityMain.getLogger().error("An error occurred during the async login process for " + player.getUsername(), e); } - } catch (Exception e) { - Component builder = Component.text("An error has occurred. Is the API down?").color(NamedTextColor.RED); - player.disconnect(builder); - } + }).schedule(); } } diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/announcement/TipChatter.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/announcement/TipChatter.java index 129fff7..0db6250 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/announcement/TipChatter.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/announcement/TipChatter.java @@ -11,8 +11,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class TipChatter { @@ -24,12 +22,9 @@ public static void startAnnouncementTipTask() { String BaseAPIURL = ZanderVelocityMain.getConfig().getString(Route.from("BaseAPIURL")); String APIKey = ZanderVelocityMain.getConfig().getString(Route.from("APIKey")); String announcementTipPrefix = ZanderVelocityMain.getConfig().getString(Route.from("announcementTipPrefix")); + int interval = ZanderVelocityMain.getConfig().getInt(Route.from("announcementTipInterval")); - // Create a ScheduledExecutorService with a single thread - ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - - // Schedule the task to run every 10 seconds - scheduler.scheduleAtFixedRate(() -> { + ZanderVelocityMain.getProxy().getScheduler().buildTask(ZanderVelocityMain.getInstance(), () -> { try { // GET request to fetch Announcement Tip. Request req = Request.builder() @@ -64,8 +59,8 @@ public static void startAnnouncementTipTask() { } catch (Exception e) { // Handle exceptions here logger.error("Announcement Tip Failed, will try again later.", e); - System.out.println("Announcement Tip Failed, will try again in " + ZanderVelocityMain.getConfig().getString(Route.from("announcementTipInterval")) + " minutes."); + System.out.println("Announcement Tip Failed, will try again in " + interval + " minutes."); } - }, 0, ZanderVelocityMain.getConfig().getInt(Route.from("announcementTipInterval")), TimeUnit.MINUTES); + }).repeat(interval, TimeUnit.MINUTES).schedule(); } -} +} \ No newline at end of file diff --git a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/api/Heartbeat.java b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/api/Heartbeat.java index ccc1bf8..263f10c 100644 --- a/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/api/Heartbeat.java +++ b/zander-velocity/src/main/java/org/modularsoft/zander/velocity/util/api/Heartbeat.java @@ -8,8 +8,6 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.modularsoft.zander.velocity.ZanderVelocityMain; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class Heartbeat { @@ -17,11 +15,7 @@ public static void startHeartbeatTask() { String BaseAPIURL = ZanderVelocityMain.getConfig().getString(Route.from("BaseAPIURL")); String APIKey = ZanderVelocityMain.getConfig().getString(Route.from("APIKey")); - // Create a ScheduledExecutorService with a single thread - ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); - - // Schedule the task to run every 60 seconds - scheduler.scheduleAtFixedRate(() -> { + ZanderVelocityMain.getProxy().getScheduler().buildTask(ZanderVelocityMain.getInstance(), () -> { try { // Your existing code here // GET request to link to rules. @@ -57,6 +51,6 @@ public static void startHeartbeatTask() { player.disconnect(message); }); } - }, 0, 60, TimeUnit.SECONDS); + }).repeat(60, TimeUnit.SECONDS).schedule(); } -} +} \ No newline at end of file