package net.pterodactylus.rhynodge.engine;
-import static java.lang.System.currentTimeMillis;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function0;
+import kotlin.jvm.functions.Function1;
+import net.pterodactylus.rhynodge.Reaction;
+import net.pterodactylus.rhynodge.actions.EmailAction;
+import net.pterodactylus.rhynodge.states.StateManager;
+import org.apache.log4j.Logger;
import java.util.Map;
import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.*;
-import net.pterodactylus.rhynodge.Reaction;
-import net.pterodactylus.rhynodge.states.StateManager;
+import static java.lang.System.currentTimeMillis;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static net.pterodactylus.util.exception.ExceptionsKt.suppressException;
/**
* Rhynodge main engine.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
+@Singleton
public class Engine {
private final StateManager stateManager;
private final ScheduledExecutorService executorService;
private final Map<String, Future<?>> scheduledFutures = new ConcurrentHashMap<>();
+ private final EmailAction errorEmailAction;
- /**
- * Creates a new engine.
- *
- * @param stateManager
- * The state manager
- */
- public Engine(StateManager stateManager) {
+ @Inject
+ public Engine(StateManager stateManager, EmailAction errorEmailAction) {
this.stateManager = stateManager;
- executorService = new ScheduledThreadPoolExecutor(10);
+ this.errorEmailAction = errorEmailAction;
+ executorService = new ScheduledThreadPoolExecutor(1);
}
//
Optional<net.pterodactylus.rhynodge.State> lastState = reactionState.loadLastState();
long lastExecutionTime = lastState.map(net.pterodactylus.rhynodge.State::time).orElse(0L);
long nextExecutionTime = lastExecutionTime + reaction.updateInterval();
- ReactionRunner reactionRunner = new ReactionRunner(reaction, reactionState);
- ScheduledFuture<?> future = executorService.scheduleWithFixedDelay(reactionRunner, nextExecutionTime - currentTimeMillis(), reaction.updateInterval(), MILLISECONDS);
+ ReactionRunner reactionRunner = new ReactionRunner(reaction, reactionState, errorEmailAction);
+ ScheduledFuture<?> future = executorService.scheduleWithFixedDelay(suppressException(wrapRunnable(reactionRunner), logExceptionForReaction(reaction))::invoke, nextExecutionTime - currentTimeMillis(), reaction.updateInterval(), MILLISECONDS);
scheduledFutures.put(name, future);
}
+ private Function1<Exception, Unit> logExceptionForReaction(Reaction reaction) {
+ return (Exception e) -> {
+ logger.warn("Exception during Reaction “%s”!".formatted(reaction.name()), e);
+ return Unit.INSTANCE;
+ };
+ }
+
+ private Function0<Unit> wrapRunnable(Runnable runnable) {
+ return () -> {
+ runnable.run();
+ return Unit.INSTANCE;
+ };
+ }
+
/**
* Removes the reaction with the given name.
*
scheduledFutures.remove(name).cancel(true);
}
+ private static final Logger logger = Logger.getLogger(Engine.class);
+
}