diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/job/CommandCooldownMapCleanupJob.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/job/CommandCooldownMapCleanupJob.java new file mode 100644 index 000000000..cc3deba06 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/job/CommandCooldownMapCleanupJob.java @@ -0,0 +1,31 @@ +package dev.sheldan.abstracto.core.command.job; + +import dev.sheldan.abstracto.core.command.service.CommandCoolDownServiceBean; +import lombok.extern.slf4j.Slf4j; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.PersistJobDataAfterExecution; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.quartz.QuartzJobBean; +import org.springframework.stereotype.Component; + +@Slf4j +@DisallowConcurrentExecution +@Component +@PersistJobDataAfterExecution +public class CommandCooldownMapCleanupJob extends QuartzJobBean { + + @Autowired + private CommandCoolDownServiceBean commandCoolDownServiceBean; + + @Override + protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { + try { + log.info("Executing command cooldown cleanup job."); + commandCoolDownServiceBean.cleanUpCooldownStorage(); + } catch (Exception exception) { + log.error("Command cooldown cleanup job failed.", exception); + } + } +} diff --git a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownServiceBean.java b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownServiceBean.java index a2c577dc4..626e80b54 100644 --- a/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownServiceBean.java +++ b/abstracto-application/core/core-impl/src/main/java/dev/sheldan/abstracto/core/command/service/CommandCoolDownServiceBean.java @@ -21,9 +21,11 @@ import dev.sheldan.abstracto.core.service.management.CoolDownChannelGroupManagem import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; import java.time.Duration; import java.time.Instant; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -235,6 +237,9 @@ public class CommandCoolDownServiceBean implements CommandCoolDownService { } try { Duration coolDown = getServerCoolDownForCommand(command, serverId); + if(coolDown.equals(Duration.ZERO)) { + return; + } Instant newExecutionPoint = Instant.now().plus(coolDown); String commandName = command.getConfiguration().getName(); Map serverCoolDowns = storage.getServerCoolDowns(); @@ -258,6 +263,9 @@ public class CommandCoolDownServiceBean implements CommandCoolDownService { } try { Duration coolDown = getChannelGroupCoolDownForCommand(command, serverIdChannelId); + if(coolDown.equals(Duration.ZERO)) { + return; + } Instant newExecutionPoint = Instant.now().plus(coolDown); String commandName = command.getConfiguration().getName(); Long serverId = serverIdChannelId.getServerId(); @@ -322,8 +330,11 @@ public class CommandCoolDownServiceBean implements CommandCoolDownService { takeLock(); } try { - Long serverId = serverChannelUserId.getGuildId(); Duration coolDown = getMemberCoolDownForCommand(command, serverChannelUserId.toServerChannelId()); + if(coolDown.equals(Duration.ZERO)) { + return; + } + Long serverId = serverChannelUserId.getGuildId(); Instant newExecutionPoint = Instant.now().plus(coolDown); String commandName = command.getConfiguration().getName(); Map> serverMemberCoolDowns = storage.getMemberCoolDowns(); @@ -398,4 +409,38 @@ public class CommandCoolDownServiceBean implements CommandCoolDownService { reUseTimes.put(commandName, newExecutionPoint); return CommandReUseMap.builder().reUseTimes(reUseTimes).build(); } + + @Transactional + public void cleanUpCooldownStorage() { + takeLock(); + try { + cleanUpLongReUseMap(storage.getServerCoolDowns()); + cleanUpLongLongReUseMap(storage.getMemberCoolDowns()); + cleanUpLongLongReUseMap(storage.getChannelGroupCoolDowns()); + } finally { + releaseLock(); + } + } + + private void cleanUpLongLongReUseMap(Map> longLongReuseMap) { + longLongReuseMap.forEach((aLong, longCommandReUseMapMap) -> cleanUpLongReUseMap(longCommandReUseMapMap)); + longLongReuseMap.entrySet().removeIf(longMapEntry -> longMapEntry.getValue().isEmpty()); + } + + private void cleanUpLongReUseMap(Map map) { + map.forEach((aLong, commandReUseMap) -> cleanUpReUseMap(commandReUseMap)); + map.entrySet().removeIf(longCommandReUseMapEntry -> longCommandReUseMapEntry.getValue().getReUseTimes().isEmpty()); + } + + private void cleanUpReUseMap(CommandReUseMap commandReUseMap) { + List commandsToRemove = new ArrayList<>(); + Instant now = Instant.now(); + commandReUseMap.getReUseTimes().forEach((commandName, reUseTime) -> { + if(reUseTime.isBefore(now)) { + commandsToRemove.add(commandName); + } + }); + log.debug("Deleting {} command mappings.", commandsToRemove.size()); + commandsToRemove.forEach(commandName -> commandReUseMap.getReUseTimes().remove(commandName)); + } } diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/command_cooldown_cleanup_job.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/command_cooldown_cleanup_job.xml new file mode 100644 index 000000000..5c14347e8 --- /dev/null +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/command_cooldown_cleanup_job.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/data.xml b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/data.xml index a5d988ec2..ebff7b23e 100644 --- a/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/data.xml +++ b/abstracto-application/core/core-impl/src/main/resources/migrations/1.2.9-core/core-seedData/data.xml @@ -8,4 +8,5 @@ http://www.liquibase.org/xml/ns/pro ../../dbchangelog-3.8.xsd" > + \ No newline at end of file