use of net.kodehawa.mantarobot.core.listeners.events.ShardMonitorEvent in project MantaroBot by Mantaro.
the class CommandListener method onEvent.
@Override
public void onEvent(Event event) {
if (event instanceof ShardMonitorEvent) {
if (MantaroBot.getInstance().getShardedMantaro().getShards()[shardId].getEventManager().getLastJDAEventTimeDiff() > 30000)
return;
// Hey, this listener is alive! (This won't pass if somehow this is blocked)
((ShardMonitorEvent) event).alive(shardId, ShardMonitorEvent.COMMAND_LISTENER);
return;
}
if (event instanceof GuildMessageReceivedEvent) {
GuildMessageReceivedEvent msg = (GuildMessageReceivedEvent) event;
// Inserts a cached message into the cache. This only holds the id and the content, and is way lighter than saving the entire jda object.
messageCache.put(msg.getMessage().getId(), Optional.of(new CachedMessage(msg.getAuthor().getIdLong(), msg.getMessage().getContentDisplay())));
// Ignore myself and bots.
if (msg.getAuthor().isBot() || msg.getAuthor().equals(msg.getJDA().getSelfUser()))
return;
shard.getCommandPool().execute(() -> onCommand(msg));
}
}
use of net.kodehawa.mantarobot.core.listeners.events.ShardMonitorEvent in project MantaroBot by Mantaro.
the class ShardWatcher method run.
@Override
public void run() {
LogUtils.shard("ShardWatcherThread started");
// Executes the restart queue handler. For the actual logic behind all this, check the next while(true) loop.
THREAD_POOL.execute(() -> {
while (true) {
MantaroShard shard = RESTART_QUEUE.poll();
if (shard == null) {
// poll the queue every 10 seconds
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
LogUtils.shard("Shard restarter task interrupted");
return;
}
// Continue to the next loop cycle if no shard is on the restart queue.
continue;
}
// Alert us, plz no panic
LogUtils.shard(String.format("(Resume request failed or errored) " + "Dead shard? Starting automatic shard restart on shard #%d due to it being inactive for longer than 30 seconds.", shard.getId()));
try {
// Reboot the shard.
shard.start(true);
} catch (Exception e) {
// If the shard wasn't able to restart by itself, alert us so we can reboot manually later.
LogUtils.shard(String.format("Shard %d was unable to be restarted: %s", shard.getId(), e));
}
try {
// Wait 5 seconds as a backoff.
Thread.sleep(5000);
} catch (InterruptedException e) {
LogUtils.shard("Shard restarter task interrupted");
return;
}
}
});
final int wait = MantaroData.config().get().shardWatcherWait;
while (true) {
try {
// Run every x ms (usually every 10 minutes unless changed)
Thread.sleep(wait);
MantaroEventManager.getLog().info("Checking shards...");
// Just in case...
if (shardedMantaro == null)
shardedMantaro = MantaroBot.getInstance().getShardedMantaro();
// Get and propagate the shard event.
// This event will propagate over all Mantaro-specific listeners, and see if the shards are responding accordingly.
ShardMonitorEvent sme = new ShardMonitorEvent(shardedMantaro.getTotalShards());
EventUtils.propagateEvent(sme);
// Start the procedure...
int[] dead = sme.getDeadShards();
// Oh well... we can try to recover them now!
if (dead.length != 0) {
MantaroEventManager.getLog().error("Dead shards found: {}", Arrays.toString(dead));
// restart on..." kinda message.
if (dead.length > 15) {
LogUtils.shard("Seems like Megumin struck our castle and we got a horribly high amount of dead shards (" + dead.length + ")\n" + "This could be just due to them reconnecting though, if nothing appears down there talking about how the shards are rebooting " + "you might aswell ignore this warning.");
}
// Under the hood this basically calls for a RESUME JDA instance and if it fails, it adds it to the restart queue to replace it with a completely new one.
for (int id : dead) {
try {
MantaroShard shard = MantaroBot.getInstance().getShard(id);
// But, if the shard has been inactive for too long, we're better off scrapping this session as the shard might be stuck on connecting.
if ((shard.getStatus() == JDA.Status.RECONNECT_QUEUED || shard.getStatus() == JDA.Status.ATTEMPTING_TO_RECONNECT || shard.getStatus() == JDA.Status.SHUTDOWN) && shard.getEventManager().getLastJDAEventTimeDiff() < 200000) {
LogUtils.shard(String.format("Skipping shard %d due to it being currently reconnecting to the websocket or was shutdown manually...", id));
continue;
}
LogUtils.shard(String.format("Found dead shard (#%d)... attempting RESUME request and waiting 20 seconds to validate.", id));
// Send the RESUME request.
((JDAImpl) (shard.getJDA())).getClient().close(4000);
RESUME_WAITER.schedule(() -> {
if (shard.getEventManager().getLastJDAEventTimeDiff() > 18000) {
RESTART_QUEUE.add(shard);
}
}, 20, TimeUnit.SECONDS);
} catch (Exception e) {
// Print the exception so we can look at it later...
e.printStackTrace();
// Force add into the queue
RESUME_WAITER.schedule(() -> RESTART_QUEUE.add(MantaroBot.getInstance().getShard(id)), 30, TimeUnit.SECONDS);
// Somehow we couldn't reboot the shard.
LogUtils.shard(String.format("Cannot restart shard %d. Try to do it manually.", id));
}
}
} else {
// yay
MantaroEventManager.getLog().info("No dead shards found");
long ping = MantaroBot.getInstance().getPing();
// We might have a few soft-dead shards on here... (or internet went to shit)
if (ping > 400) {
LogUtils.shard(String.format("No dead shards found, but average ping is high (%dms). Ping breakdown: %s", ping, Arrays.toString(MantaroBot.getInstance().getPings())));
}
}
} catch (InterruptedException e) {
// Just in case we stop this for any reason, we want to know that we interrupted this, just so we know we won't have a shard watcher running on the background.
log.error("ShardWatcher interrupted, stopping...");
LogUtils.shard("ShardWatcher interrupted, stopping...");
return;
}
}
}
use of net.kodehawa.mantarobot.core.listeners.events.ShardMonitorEvent in project MantaroBot by Mantaro.
the class MantaroListener method onEvent.
@Override
public void onEvent(Event event) {
if (event instanceof ShardMonitorEvent) {
if (MantaroBot.getInstance().getShardedMantaro().getShards()[shardId].getEventManager().getLastJDAEventTimeDiff() > 30000)
return;
((ShardMonitorEvent) event).alive(shardId, ShardMonitorEvent.MANTARO_LISTENER);
return;
}
if (event instanceof GuildMessageReceivedEvent) {
MantaroBot.getInstance().getStatsClient().increment("messages_received");
GuildMessageReceivedEvent e = (GuildMessageReceivedEvent) event;
onMessage(e);
return;
}
if (event instanceof GuildMemberJoinEvent) {
shard.getThreadPool().execute(() -> onUserJoin((GuildMemberJoinEvent) event));
return;
}
if (event instanceof GuildMemberLeaveEvent) {
shard.getThreadPool().execute(() -> onUserLeave((GuildMemberLeaveEvent) event));
return;
}
// Doesn't run on the thread pool as there's no need for it.
if (event instanceof GuildMemberRoleAddEvent) {
// It only runs on the thread pool if needed.
handleNewPatron((GuildMemberRoleAddEvent) event);
}
if (event instanceof GuildMessageUpdateEvent) {
logEdit((GuildMessageUpdateEvent) event);
return;
}
if (event instanceof GuildMessageDeleteEvent) {
logDelete((GuildMessageDeleteEvent) event);
return;
}
if (event instanceof GuildUnbanEvent) {
logUnban((GuildUnbanEvent) event);
return;
}
if (event instanceof GuildBanEvent) {
logBan((GuildBanEvent) event);
return;
}
// Internal events
if (event instanceof GuildJoinEvent) {
GuildJoinEvent e = (GuildJoinEvent) event;
if (e.getGuild().getSelfMember().getJoinDate().isBefore(OffsetDateTime.now().minusSeconds(30)))
return;
onJoin(e);
if (MantaroCore.hasLoadedCompletely()) {
MantaroBot.getInstance().getStatsClient().gauge("guilds", MantaroBot.getInstance().getGuildCache().size());
MantaroBot.getInstance().getStatsClient().gauge("users", MantaroBot.getInstance().getUserCache().size());
}
return;
}
if (event instanceof GuildLeaveEvent) {
onLeave((GuildLeaveEvent) event);
if (MantaroCore.hasLoadedCompletely()) {
MantaroBot.getInstance().getStatsClient().gauge("guilds", MantaroBot.getInstance().getGuildCache().size());
MantaroBot.getInstance().getStatsClient().gauge("users", MantaroBot.getInstance().getUserCache().size());
}
return;
}
// debug
if (event instanceof StatusChangeEvent) {
logStatusChange((StatusChangeEvent) event);
return;
}
if (event instanceof DisconnectEvent) {
onDisconnect((DisconnectEvent) event);
return;
}
if (event instanceof ExceptionEvent) {
MantaroBot.getInstance().getStatsClient().increment("exceptions");
onException((ExceptionEvent) event);
return;
}
if (event instanceof HttpRequestEvent) {
MantaroBot.getInstance().getStatsClient().incrementCounter("http_requests");
return;
}
if (event instanceof ReconnectedEvent) {
MantaroBot.getInstance().getStatsClient().increment("shard.reconnect");
MantaroBot.getInstance().getStatsClient().recordEvent(com.timgroup.statsd.Event.builder().withTitle("shard.reconnect").withText("Shard reconnected").withDate(new Date()).build());
return;
}
if (event instanceof ResumedEvent) {
MantaroBot.getInstance().getStatsClient().increment("shard.resume");
MantaroBot.getInstance().getStatsClient().recordEvent(com.timgroup.statsd.Event.builder().withTitle("shard.resume").withText("Shard resumed").withDate(new Date()).build());
}
}
Aggregations