Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ dependencies {
// https://mvnrepository.com/artifact/org.apache.commons/commons-lang3
implementation("org.apache.commons:commons-lang3:3.20.0")

implementation("com.eternalcode:eternalcode-commons-shared:1.3.3")
implementation("com.eternalcode:eternalcode-commons-shared:1.3.4")
implementation("com.eternalcode:eternalcode-commons-loom:1.3.4")

implementation("dev.skywolfxp:discord-channel-html-transcript:3.0.0")
}
Expand Down
17 changes: 9 additions & 8 deletions src/main/java/com/eternalcode/discordapp/DiscordApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@
import com.eternalcode.discordapp.feature.review.command.GitHubReviewCommand;
import com.eternalcode.discordapp.feature.review.database.GitHubReviewMentionRepository;
import com.eternalcode.discordapp.feature.review.database.GitHubReviewMentionRepositoryImpl;
import com.eternalcode.discordapp.scheduler.Scheduler;
import com.eternalcode.discordapp.scheduler.VirtualThreadSchedulerImpl;
import com.eternalcode.commons.scheduler.loom.LoomScheduler;
import com.eternalcode.commons.scheduler.loom.LoomSchedulerImpl;
import com.eternalcode.commons.scheduler.loom.MainThreadDispatcher;
import com.eternalcode.discordapp.feature.ticket.TicketConfigurer;
import com.jagrosh.jdautilities.command.CommandClient;
import com.jagrosh.jdautilities.command.CommandClientBuilder;
Expand All @@ -72,7 +73,7 @@ public class DiscordApp {

private static final Logger LOGGER = LoggerFactory.getLogger(DiscordApp.class);
private static final Duration REMINDER_INTERVAL = Duration.ofHours(24);
private Scheduler scheduler;
private LoomScheduler scheduler;
private GitHubReviewReminderService reminderService;
private JDA jda;
private DatabaseManager databaseManager;
Expand Down Expand Up @@ -117,7 +118,7 @@ private void runApplication() throws Exception {

LOGGER.info("Initializing core components...");
OkHttpClient httpClient = new OkHttpClient();
Scheduler scheduler = new VirtualThreadSchedulerImpl();
LoomScheduler scheduler = new LoomSchedulerImpl(MainThreadDispatcher.synchronous());
DatabaseManager databaseManager = new DatabaseManager(databaseConfig, new File("database"));
databaseManager.connect();
ObserverRegistry observerRegistry = new ObserverRegistry();
Expand Down Expand Up @@ -219,13 +220,13 @@ private void runApplication() throws Exception {
});

LOGGER.info("Starting scheduled tasks...");
scheduler.schedule(new GuildStatisticsTask(guildStats), Duration.ofMinutes(5));
scheduler.runAsyncLater(new GuildStatisticsTask(guildStats), Duration.ofMinutes(5));
new GitHubReviewTask(reviewService, jda, scheduler).start();
scheduler.scheduleRepeating(new AutoMessageTask(autoMsgService), appConfig.autoMessagesConfig.interval);
scheduler.runAsyncTimer(new AutoMessageTask(autoMsgService), Duration.ZERO, appConfig.autoMessagesConfig.interval);

LOGGER.info("Auto messages scheduled with interval: {}", appConfig.autoMessagesConfig.interval);

scheduler.scheduleRepeating(new MeetingCleanupTask(meetingService, jda), Duration.ofHours(1));
scheduler.runAsyncTimer(new MeetingCleanupTask(meetingService, jda), Duration.ZERO, Duration.ofHours(1));

this.scheduler = scheduler;
this.reminderService = reminderService;
Expand All @@ -238,7 +239,7 @@ private void shutdown() {

try {
if (scheduler != null) {
scheduler.shutdown();
scheduler.shutdown(Duration.ofSeconds(30));
LOGGER.info("Scheduler stopped");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.eternalcode.commons.concurrent.FutureHandler;
import com.eternalcode.discordapp.config.AppConfig;
import com.eternalcode.discordapp.feature.review.database.GitHubReviewMentionRepository;
import com.eternalcode.discordapp.scheduler.Scheduler;
import com.eternalcode.commons.scheduler.loom.LoomScheduler;
import io.sentry.Sentry;
import java.io.IOException;
import java.time.Duration;
Expand All @@ -22,7 +22,7 @@ public class GitHubReviewReminderService {
private static final Duration GITHUB_API_RATE_LIMIT = Duration.ofSeconds(1);
private final JDA jda;
private final GitHubReviewMentionRepository mentionRepository;
private final Scheduler scheduler;
private final LoomScheduler scheduler;
private final Duration reminderInterval;
private final AppConfig appConfig;
private final AtomicBoolean isRunning = new AtomicBoolean(false);
Expand All @@ -31,7 +31,7 @@ public GitHubReviewReminderService(
JDA jda,
GitHubReviewMentionRepository mentionRepository,
AppConfig appConfig,
Scheduler scheduler,
LoomScheduler scheduler,
Duration reminderInterval
) {
this.jda = jda;
Expand All @@ -45,7 +45,7 @@ public void start() {
if (this.isRunning.compareAndSet(false, true)) {
LOGGER.info("Starting GitHub review reminder service with interval: " + this.reminderInterval);

this.scheduler.scheduleRepeating(
this.scheduler.runAsyncTimer(
this::sendRemindersWithErrorHandling,
Duration.ofMinutes(1),
this.reminderInterval
Expand Down Expand Up @@ -112,9 +112,7 @@ private CompletableFuture<Void> processReminders(List<GitHubReviewMentionReposit
}

private CompletableFuture<Void> delay(Duration delay) {
CompletableFuture<Void> future = new CompletableFuture<>();
this.scheduler.schedule(() -> future.complete(null), delay);
return future;
return this.scheduler.delay(delay).toCompletableFuture();
}

private CompletableFuture<Void> sendReminder(GitHubReviewMentionRepository.ReviewerReminder reminder) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.eternalcode.discordapp.feature.review;

import com.eternalcode.commons.concurrent.FutureHandler;
import com.eternalcode.discordapp.scheduler.Scheduler;
import com.eternalcode.commons.scheduler.loom.LoomScheduler;
import io.sentry.Sentry;
import java.time.Duration;
import java.util.concurrent.CompletableFuture;
Expand All @@ -20,10 +20,10 @@ public class GitHubReviewTask {

private final GitHubReviewService gitHubReviewService;
private final JDA jda;
private final Scheduler scheduler;
private final LoomScheduler scheduler;
private final AtomicBoolean isRunning = new AtomicBoolean(false);

public GitHubReviewTask(GitHubReviewService gitHubReviewService, JDA jda, Scheduler scheduler) {
public GitHubReviewTask(GitHubReviewService gitHubReviewService, JDA jda, LoomScheduler scheduler) {
this.gitHubReviewService = gitHubReviewService;
this.jda = jda;
this.scheduler = scheduler;
Expand All @@ -32,7 +32,7 @@ public GitHubReviewTask(GitHubReviewService gitHubReviewService, JDA jda, Schedu
public void start() {
if (this.isRunning.compareAndSet(false, true)) {
LOGGER.info("Starting GitHub review task with interval: {}", TASK_INTERVAL);
this.scheduler.scheduleRepeating(this::executeTask, Duration.ofMinutes(1), TASK_INTERVAL);
this.scheduler.runAsyncTimer(this::executeTask, Duration.ofMinutes(1), TASK_INTERVAL);
}
else {
LOGGER.warn("GitHub review task is already running");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import com.eternalcode.discordapp.feature.review.GitHubPullRequest;
import com.eternalcode.discordapp.feature.review.GitHubReviewMention;
import com.eternalcode.discordapp.feature.review.GitHubReviewStatus;
import com.eternalcode.discordapp.scheduler.Scheduler;
import com.eternalcode.commons.scheduler.loom.LoomScheduler;
import com.j256.ormlite.stmt.DeleteBuilder;
import com.j256.ormlite.stmt.UpdateBuilder;
import com.j256.ormlite.table.TableUtils;
Expand All @@ -28,20 +28,20 @@ public class GitHubReviewMentionRepositoryImpl extends AbstractRepository<GitHub
private static final Duration MENTION_INTERVAL = Duration.ofHours(12);
private static final Duration CLEANUP_INTERVAL = Duration.ofDays(7);

private final Scheduler scheduler;
private final LoomScheduler scheduler;

public GitHubReviewMentionRepositoryImpl(DatabaseManager databaseManager, Scheduler scheduler) {
public GitHubReviewMentionRepositoryImpl(DatabaseManager databaseManager, LoomScheduler scheduler) {
super(databaseManager, GitHubReviewMentionWrapper.class);
this.scheduler = scheduler;

this.scheduler.scheduleRepeating(
this.scheduler.runAsyncTimer(
this::performCleanup,
Duration.ofHours(1),
Duration.ofHours(24)
);
}

public static GitHubReviewMentionRepository create(DatabaseManager databaseManager, Scheduler scheduler) {
public static GitHubReviewMentionRepository create(DatabaseManager databaseManager, LoomScheduler scheduler) {
try {
TableUtils.createTableIfNotExists(databaseManager.getConnectionSource(), GitHubReviewMentionWrapper.class);
LOGGER.info("GitHubReviewMentionRepository initialized successfully");
Expand All @@ -60,7 +60,7 @@ public CompletableFuture<Void> markReviewerAsMentioned(GitHubPullRequest pullReq
return CompletableFuture.failedFuture(new IllegalArgumentException("PullRequest cannot be null"));
}

return CompletableFuture.runAsync(() -> {
return this.scheduler.<Void>supplyAsync(() -> {
try {
String mentionKey = this.createMentionKey(pullRequest, userId);
GitHubReviewMentionWrapper mention = this.select(mentionKey).join()
Expand All @@ -80,13 +80,14 @@ public CompletableFuture<Void> markReviewerAsMentioned(GitHubPullRequest pullReq

this.save(mention).join();
LOGGER.info("Marked reviewer as mentioned: userId=" + userId + ", PR=" + pullRequest.toUrl());
return null;
}
catch (Exception exception) {
Sentry.captureException(exception);
LOGGER.log(Level.SEVERE, "Error marking reviewer as mentioned", exception);
throw new DataAccessException("Failed to mark reviewer as mentioned", exception);
}
}).exceptionally(FutureHandler::handleException);
}).toCompletableFuture().exceptionally(FutureHandler::handleException);
}

@Override
Expand All @@ -95,7 +96,7 @@ public CompletableFuture<Boolean> isMentioned(GitHubPullRequest pullRequest, lon
return CompletableFuture.completedFuture(false);
}

return CompletableFuture.supplyAsync(() -> {
return this.scheduler.supplyAsync(() -> {
try {
String mentionKey = this.createMentionKey(pullRequest, userId);
GitHubReviewMentionWrapper mention = this.select(mentionKey).join().orElse(null);
Expand All @@ -117,7 +118,7 @@ public CompletableFuture<Boolean> isMentioned(GitHubPullRequest pullRequest, lon
LOGGER.log(Level.SEVERE, "Error checking if user is mentioned", exception);
return false;
}
}).exceptionally(throwable -> {
}).toCompletableFuture().exceptionally(throwable -> {
Sentry.captureException(throwable);
LOGGER.log(Level.SEVERE, "Exception in isMentioned", throwable);
return false;
Expand All @@ -130,7 +131,7 @@ public CompletableFuture<Void> recordReminderSent(GitHubPullRequest pullRequest,
return CompletableFuture.failedFuture(new IllegalArgumentException("PullRequest cannot be null"));
}

return CompletableFuture.runAsync(() -> {
return this.scheduler.<Void>supplyAsync(() -> {
try {
String mentionKey = this.createMentionKey(pullRequest, userId);
GitHubReviewMentionWrapper mention = this.select(mentionKey).join().orElse(null);
Expand All @@ -144,18 +145,19 @@ public CompletableFuture<Void> recordReminderSent(GitHubPullRequest pullRequest,
LOGGER.warning("Mention not found when recording reminder: userId=" + userId + ", PR="
+ pullRequest.toUrl());
}
return null;
}
catch (Exception exception) {
Sentry.captureException(exception);
LOGGER.log(Level.SEVERE, "Error recording reminder sent", exception);
throw new DataAccessException("Failed to record reminder sent", exception);
}
}).exceptionally(FutureHandler::handleException);
}).toCompletableFuture().exceptionally(FutureHandler::handleException);
}

@Override
public CompletableFuture<List<ReviewerReminder>> getReviewersNeedingReminders(Duration reminderInterval) {
return CompletableFuture.supplyAsync(() -> {
return this.scheduler.supplyAsync(() -> {
List<ReviewerReminder> reminders = new ArrayList<>();

try {
Expand Down Expand Up @@ -200,7 +202,7 @@ public CompletableFuture<List<ReviewerReminder>> getReviewersNeedingReminders(Du
}

return reminders;
}).exceptionally(throwable -> {
}).toCompletableFuture().exceptionally(throwable -> {
Sentry.captureException(throwable);
LOGGER.log(Level.SEVERE, "Exception in getReviewersNeedingReminders", throwable);
return new ArrayList<>();
Expand All @@ -213,7 +215,7 @@ public CompletableFuture<GitHubReviewMention> find(String pullRequest, long user
return CompletableFuture.completedFuture(null);
}

return CompletableFuture.supplyAsync(() -> {
return this.scheduler.supplyAsync(() -> {
try {
String mentionKey = this.createMentionKey(pullRequest, userId);
GitHubReviewMentionWrapper wrapper = this.select(mentionKey).join().orElse(null);
Expand All @@ -224,7 +226,7 @@ public CompletableFuture<GitHubReviewMention> find(String pullRequest, long user
LOGGER.log(Level.SEVERE, "Database error finding review mention", exception);
throw new DataAccessException("Failed to find review mention", exception);
}
}).exceptionally(throwable -> {
}).toCompletableFuture().exceptionally(throwable -> {
Sentry.captureException(throwable);
LOGGER.log(Level.SEVERE, "Exception in find", throwable);
return null;
Expand All @@ -237,7 +239,7 @@ public CompletableFuture<Integer> updateReviewStatus(GitHubPullRequest pullReque
return CompletableFuture.completedFuture(0);
}

return CompletableFuture.supplyAsync(() -> {
return this.scheduler.supplyAsync(() -> {
try {
UpdateBuilder<GitHubReviewMentionWrapper, Object> updateBuilder =
this.databaseManager.getDao(GitHubReviewMentionWrapper.class).updateBuilder();
Expand All @@ -252,7 +254,7 @@ public CompletableFuture<Integer> updateReviewStatus(GitHubPullRequest pullReque
LOGGER.log(Level.SEVERE, "Error updating review status", exception);
throw new DataAccessException("Failed to update review status", exception);
}
}).exceptionally(throwable -> {
}).toCompletableFuture().exceptionally(throwable -> {
Sentry.captureException(throwable);
LOGGER.log(Level.SEVERE, "Exception in updateReviewStatus", throwable);
return 0;
Expand All @@ -268,7 +270,7 @@ private String createMentionKey(String pullRequestUrl, long userId) {
}

public CompletableFuture<Integer> cleanupOldMentions(Duration maxAge) {
return CompletableFuture.supplyAsync(() -> {
return this.scheduler.supplyAsync(() -> {
try {
Instant cutoffTime = Instant.now().minus(maxAge);
long cutoffTimeMillis = cutoffTime.toEpochMilli();
Expand All @@ -294,7 +296,7 @@ public CompletableFuture<Integer> cleanupOldMentions(Duration maxAge) {
LOGGER.log(Level.SEVERE, "Error cleaning up old mentions", exception);
throw new DataAccessException("Failed to cleanup old mentions", exception);
}
}).exceptionally(throwable -> {
}).toCompletableFuture().exceptionally(throwable -> {
Sentry.captureException(throwable);
LOGGER.log(Level.SEVERE, "Exception in cleanupOldMentions", throwable);
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.eternalcode.discordapp.config.AppConfig;
import com.eternalcode.discordapp.config.ConfigManager;
import com.eternalcode.discordapp.database.DatabaseManager;
import com.eternalcode.discordapp.scheduler.Scheduler;
import com.eternalcode.commons.scheduler.loom.LoomScheduler;
import com.eternalcode.discordapp.feature.ticket.command.TicketCommand;
import com.eternalcode.discordapp.feature.ticket.panel.TicketPanelController;
import com.eternalcode.discordapp.feature.ticket.panel.TicketPanelService;
Expand All @@ -24,15 +24,15 @@ public class TicketConfigurer {
private final JDA jda;
private final ConfigManager configManager;
private final DatabaseManager databaseManager;
private final Scheduler scheduler;
private final LoomScheduler scheduler;
private final CommandClientBuilder commandClientBuilder;
private final AppConfig appConfig;

public TicketConfigurer(
JDA jda,
ConfigManager configManager,
DatabaseManager databaseManager,
Scheduler scheduler,
LoomScheduler scheduler,
CommandClientBuilder commandClientBuilder,
AppConfig appConfig
) {
Expand Down Expand Up @@ -99,15 +99,15 @@ public void initialize() {
// Schedules a task that periodically cleans up inactive tickets.
// If an administrator deletes a ticket channel manually instead of clicking "Close ticket",
// the record may remain in the database — this task removes such leftovers.
this.scheduler.scheduleRepeating(
this.scheduler.runAsyncTimer(
() -> {
try {
ticketChannelService.cleanupInactiveTickets().join();
}
catch (Exception exception) {
LOGGER.error("Error during ticket cleanup", exception);
}
}, TICKET_CLEANUP_FREQUENCY);
}, Duration.ZERO, TICKET_CLEANUP_FREQUENCY);
}
catch (Exception exception) {
LOGGER.error("Failed to initialize ticket system", exception);
Expand Down
16 changes: 0 additions & 16 deletions src/main/java/com/eternalcode/discordapp/scheduler/Scheduler.java

This file was deleted.

Loading
Loading