Skip to content

Commit

Permalink
feat: implement rate limit solution
Browse files Browse the repository at this point in the history
This commit slows down the processing of event queues for the sole
purpose of preventing Discord API endpoint saturation as well as to
avoid the global Discord API Gateway rate limiter.

Moreover, it removes a few 'static' keywords that should not be there.
  • Loading branch information
christolis committed May 16, 2024
1 parent c638d7e commit ed46d62
Showing 1 changed file with 22 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import net.dv8tion.jda.api.events.guild.voice.GuildVoiceUpdateEvent;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.togetherjava.tjbot.config.Config;
import org.togetherjava.tjbot.features.VoiceReceiverAdapter;
Expand All @@ -19,6 +21,8 @@
import java.util.Optional;
import java.util.Queue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.regex.Matcher;
Expand All @@ -41,14 +45,22 @@
*/
public class DynamicVoiceListener extends VoiceReceiverAdapter {

private final Logger logger = LoggerFactory.getLogger(DynamicVoiceListener.class);

private final Map<String, Predicate<String>> channelPredicates = new HashMap<>();
private static final Pattern channelTopicPattern = Pattern.compile("(\\s+\\d+)$");

/** Map of event queues for each channel topic. */
private static final Map<String, Queue<GuildVoiceUpdateEvent>> eventQueues = new HashMap<>();
private final Map<String, Queue<GuildVoiceUpdateEvent>> eventQueues = new HashMap<>();

/** Map to track if an event queue is currently being processed for each channel topic. */
private static final Map<String, AtomicBoolean> activeQueuesMap = new HashMap<>();
private final Map<String, AtomicBoolean> activeQueuesMap = new HashMap<>();

/** Boolean to track if events from all queues should be handled at a slower rate. */
private final AtomicBoolean slowmode = new AtomicBoolean(false);
private final Executor eventQueueExecutor =
CompletableFuture.delayedExecutor(1L, TimeUnit.SECONDS);
private static final int SLOWMODE_THRESHOLD = 5;

/**
* Initializes a new {@link DynamicVoiceListener} with the specified configuration.
Expand Down Expand Up @@ -85,11 +97,19 @@ private void insertEventToQueue(GuildVoiceUpdateEvent event, String channelTopic
}

eventQueue.add(event);
slowmode.set(eventQueue.size() >= SLOWMODE_THRESHOLD);

if (activeQueuesMap.get(channelTopic).get()) {
return;
}

if (slowmode.get()) {
logger.info("Running with slowmode");
CompletableFuture.runAsync(() -> processEventFromQueue(channelTopic),
eventQueueExecutor);
return;
}

processEventFromQueue(channelTopic);
}

Expand Down

0 comments on commit ed46d62

Please sign in to comment.