Search in sources :

Example 1 with CommandExecutionQueueManager

use of net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager in project aiode by robinfriedli.

the class CleanDbCommand method runAdmin.

@Override
public void runAdmin() {
    Aiode.shutdownListeners();
    try {
        if (!argumentSet("silent")) {
            EmbedBuilder embedBuilder = new EmbedBuilder();
            embedBuilder.setTitle("Scheduled cleanup");
            embedBuilder.setDescription("Aiode is suspending for a few seconds to clean the database.");
            sendToActiveGuilds(embedBuilder.build());
        }
        CommandExecutionQueueManager executionQueueManager = Aiode.get().getExecutionQueueManager();
        Command command = this;
        Thread cleanupThread = new Thread(() -> {
            ThreadContext.Current.install(command);
            try {
                try {
                    executionQueueManager.joinAll(60000);
                } catch (InterruptedException e) {
                    return;
                }
                StaticSessionProvider.consumeSession(this::doClean);
            } finally {
                Aiode.registerListeners();
            }
        });
        cleanupThread.setName("database-cleanup-thread-" + command.getContext().toString());
        Thread.UncaughtExceptionHandler commandExecutionExceptionHandler = Thread.currentThread().getUncaughtExceptionHandler();
        if (commandExecutionExceptionHandler != null) {
            cleanupThread.setUncaughtExceptionHandler(commandExecutionExceptionHandler);
        }
        cleanupThread.start();
    } catch (Throwable e) {
        Aiode.registerListeners();
        throw e;
    }
}
Also used : EmbedBuilder(net.dv8tion.jda.api.EmbedBuilder) Command(net.robinfriedli.aiode.command.Command) AbstractAdminCommand(net.robinfriedli.aiode.command.AbstractAdminCommand) CommandExecutionQueueManager(net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager)

Example 2 with CommandExecutionQueueManager

use of net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager in project aiode by robinfriedli.

the class Aiode method shutdown.

/**
 * Shutdown the bot waiting for pending commands and rest actions. Note that #shutdownListeners usually should get
 * called first, as all ThreadExecutionQueues will close, meaning the CommandListener will fail. You should also be
 * careful to not call this method from within a CommandExecutionThread executed by a ThreadExecutionQueue, as this
 * method waits for those threads to finish, causing a deadlock.
 *
 * @param millisToWait    time to wait for pending actions to complete in milliseconds, after this time the bot will
 *                        quit either way
 * @param messagesToAwait list of shutdown notification messages that are being send that should first be awaited
 */
public static void shutdown(int millisToWait, @Nullable List<CompletableFuture<Message>> messagesToAwait) {
    Aiode aiode = get();
    shuttingDown = true;
    LOGGER.info("Shutting down");
    ShardManager shardManager = aiode.getShardManager();
    CommandExecutionQueueManager executionQueueManager = aiode.getExecutionQueueManager();
    // use a daemon thread to shutdown the bot after the provided time has elapsed without keeping the application
    // running if all live threads terminate earlier
    Thread forceShutdownThread = new Thread(() -> {
        try {
            Thread.sleep(millisToWait);
        } catch (InterruptedException e) {
            return;
        }
        System.exit(0);
    });
    forceShutdownThread.setDaemon(true);
    forceShutdownThread.setName("force shutdown thread");
    forceShutdownThread.start();
    executionQueueManager.closeAll();
    executionQueueManager.cancelEnqueued();
    try {
        LOGGER.info("Waiting for commands to finish");
        executionQueueManager.joinAll(0);
        if (messagesToAwait != null && !messagesToAwait.isEmpty()) {
            for (CompletableFuture<Message> futureMessage : messagesToAwait) {
                try {
                    futureMessage.get();
                } catch (InterruptedException e) {
                    break;
                } catch (ExecutionException e) {
                    continue;
                }
            }
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        forceShutdownThread.interrupt();
        return;
    }
    LOGGER.info("Shutting down registered shutdownables");
    SHUTDOWNABLES.forEach(shutdownable -> shutdownable.shutdown(millisToWait));
    LOGGER.info("Shutting down JDA");
    shardManager.shutdown();
    LOGGER.info("Shutting down hibernate SessionFactory");
    aiode.getSessionFactory().close();
    LOGGER.info("Close spring ApplicationContext");
    aiode.getSpringBootContext().close();
}
Also used : Message(net.dv8tion.jda.api.entities.Message) ShardManager(net.dv8tion.jda.api.sharding.ShardManager) ExecutionException(java.util.concurrent.ExecutionException) CommandExecutionQueueManager(net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager)

Example 3 with CommandExecutionQueueManager

use of net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager in project aiode by robinfriedli.

the class AbortCommand method doRun.

@Override
public void doRun() {
    CommandExecutionTask commandExecutionTask = getTask();
    Thread abortThread = new Thread(() -> {
        if (commandExecutionTask != null) {
            try {
                commandExecutionTask.await();
            } catch (InterruptedException ignored) {
            }
        }
        CommandExecutionQueueManager executionQueueManager = Aiode.get().getExecutionQueueManager();
        GuildContext guildContext = getContext().getGuildContext();
        ThreadExecutionQueue executionQueue = executionQueueManager.getForGuild(getContext().getGuild());
        PooledTrackLoadingExecutor pooledTrackLoadingExecutor = guildContext.getPooledTrackLoadingExecutor();
        ReplaceableTrackLoadingExecutor replaceableTrackLoadingExecutor = guildContext.getReplaceableTrackLoadingExecutor();
        if (executionQueue.isIdle() && pooledTrackLoadingExecutor.isIdle() && replaceableTrackLoadingExecutor.isIdle()) {
            EmbedBuilder embedBuilder = new EmbedBuilder();
            embedBuilder.setDescription("No commands are currently running");
            getMessageService().sendTemporary(embedBuilder, getContext().getChannel());
            setFailed(true);
        } else {
            executionQueue.abortAll();
            pooledTrackLoadingExecutor.abortAll();
            replaceableTrackLoadingExecutor.abort();
            sendSuccess("Sent all currently running commands an interrupt signal and cancelled queued commands.");
        }
    });
    abortThread.setName("aiode abort thread");
    abortThread.setUncaughtExceptionHandler(new LoggingUncaughtExceptionHandler());
    abortThread.start();
}
Also used : CommandExecutionTask(net.robinfriedli.aiode.concurrent.CommandExecutionTask) GuildContext(net.robinfriedli.aiode.discord.GuildContext) PooledTrackLoadingExecutor(net.robinfriedli.aiode.audio.exec.PooledTrackLoadingExecutor) EmbedBuilder(net.dv8tion.jda.api.EmbedBuilder) ReplaceableTrackLoadingExecutor(net.robinfriedli.aiode.audio.exec.ReplaceableTrackLoadingExecutor) ThreadExecutionQueue(net.robinfriedli.aiode.concurrent.ThreadExecutionQueue) LoggingUncaughtExceptionHandler(net.robinfriedli.aiode.exceptions.handler.handlers.LoggingUncaughtExceptionHandler) CommandExecutionQueueManager(net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager)

Example 4 with CommandExecutionQueueManager

use of net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager in project aiode by robinfriedli.

the class ClearAbandonedGuildContextsTask method run.

@Override
protected void run(JobExecutionContext jobExecutionContext) {
    Aiode aiode = Aiode.get();
    ShardManager shardManager = aiode.getShardManager();
    GuildManager guildManager = aiode.getGuildManager();
    CommandExecutionQueueManager executionQueueManager = aiode.getExecutionQueueManager();
    int removedGuilds = 0;
    for (GuildContext guildContext : guildManager.getGuildContexts()) {
        Guild guild = guildContext.retrieveGuild();
        if (guild == null || shardManager.getGuildById(guild.getIdLong()) == null) {
            guildManager.removeGuild(guild);
            executionQueueManager.removeGuild(guild);
            ++removedGuilds;
        }
    }
    if (removedGuilds > 0) {
        LoggerFactory.getLogger(getClass()).info("Destroyed context for " + removedGuilds + " missing guilds");
    }
}
Also used : GuildContext(net.robinfriedli.aiode.discord.GuildContext) GuildManager(net.robinfriedli.aiode.discord.GuildManager) ShardManager(net.dv8tion.jda.api.sharding.ShardManager) Guild(net.dv8tion.jda.api.entities.Guild) Aiode(net.robinfriedli.aiode.Aiode) CommandExecutionQueueManager(net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager)

Example 5 with CommandExecutionQueueManager

use of net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager in project aiode by robinfriedli.

the class StartupListener method onReady.

@Override
public void onReady(@NotNull ReadyEvent event) {
    STARTUP_TASK_EXECUTOR.execute(() -> {
        JDA jda = event.getJDA();
        if (discordBotListAPI != null) {
            try {
                JDA.ShardInfo shardInfo = jda.getShardInfo();
                discordBotListAPI.setStats(shardInfo.getShardId(), shardInfo.getShardTotal(), (int) jda.getGuildCache().size());
            } catch (Exception e) {
                logger.error("Exception setting discordBotListAPI stats", e);
            }
        }
        CommandExecutionQueueManager executionQueueManager = aiode.getExecutionQueueManager();
        GuildManager guildManager = aiode.getGuildManager();
        StaticSessionProvider.consumeSession(session -> {
            // setup current thread session and handle all guilds within one session instead of opening a new session for each
            for (Guild guild : jda.getGuilds()) {
                executionQueueManager.addGuild(guild);
                guildManager.addGuild(guild);
            }
        });
        for (StartupTaskContribution element : startupTaskContributions) {
            if (element.getAttribute("runForEachShard").getBool()) {
                try {
                    element.instantiate().runTask(jda);
                } catch (Exception e) {
                    String msg = String.format("Startup task %s has thrown an exception for shard %s", element.getAttribute("implementation").getValue(), jda);
                    logger.error(msg, e);
                }
            }
        }
    });
}
Also used : GuildManager(net.robinfriedli.aiode.discord.GuildManager) JDA(net.dv8tion.jda.api.JDA) StartupTaskContribution(net.robinfriedli.aiode.entities.xml.StartupTaskContribution) Guild(net.dv8tion.jda.api.entities.Guild) CommandExecutionQueueManager(net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager)

Aggregations

CommandExecutionQueueManager (net.robinfriedli.aiode.concurrent.CommandExecutionQueueManager)5 EmbedBuilder (net.dv8tion.jda.api.EmbedBuilder)2 Guild (net.dv8tion.jda.api.entities.Guild)2 ShardManager (net.dv8tion.jda.api.sharding.ShardManager)2 GuildContext (net.robinfriedli.aiode.discord.GuildContext)2 GuildManager (net.robinfriedli.aiode.discord.GuildManager)2 ExecutionException (java.util.concurrent.ExecutionException)1 JDA (net.dv8tion.jda.api.JDA)1 Message (net.dv8tion.jda.api.entities.Message)1 Aiode (net.robinfriedli.aiode.Aiode)1 PooledTrackLoadingExecutor (net.robinfriedli.aiode.audio.exec.PooledTrackLoadingExecutor)1 ReplaceableTrackLoadingExecutor (net.robinfriedli.aiode.audio.exec.ReplaceableTrackLoadingExecutor)1 AbstractAdminCommand (net.robinfriedli.aiode.command.AbstractAdminCommand)1 Command (net.robinfriedli.aiode.command.Command)1 CommandExecutionTask (net.robinfriedli.aiode.concurrent.CommandExecutionTask)1 ThreadExecutionQueue (net.robinfriedli.aiode.concurrent.ThreadExecutionQueue)1 StartupTaskContribution (net.robinfriedli.aiode.entities.xml.StartupTaskContribution)1 LoggingUncaughtExceptionHandler (net.robinfriedli.aiode.exceptions.handler.handlers.LoggingUncaughtExceptionHandler)1