Periodically remove older database entries

So far, the removal of database entries older than the configured value
of 'maxAge' was done synchronously at the plugin startup. This approach
has two downsides: first, it can delay the plugin load and, second, if
the plugin is not reloaded in a long time (which is desirable), the old
entries accumulate on the database.

Implement a periodic task that removes old entries from the database
every day at 23 hours.

Change-Id: I19e3ca9149e93fdb02f8630182b8bd85843611f0
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/EventsLogCleaner.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/EventsLogCleaner.java
index e347341..3c152e8 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/EventsLogCleaner.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/EventsLogCleaner.java
@@ -18,17 +18,25 @@
 import com.google.gerrit.extensions.events.ProjectDeletedListener;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import java.time.Duration;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 @Singleton
 public class EventsLogCleaner implements ProjectDeletedListener {
+  private static final int HOUR = 23;
+  private static final long INTERVAL = TimeUnit.DAYS.toSeconds(1);
+
   private final SQLClient eventsDb;
+
   private ScheduledThreadPoolExecutor pool;
 
   @Inject
   EventsLogCleaner(
-      @EventsDb SQLClient eventsDb,
-      @EventCleanerPool ScheduledThreadPoolExecutor pool) {
+      @EventsDb SQLClient eventsDb, @EventCleanerPool ScheduledThreadPoolExecutor pool) {
     this.eventsDb = eventsDb;
     this.pool = pool;
   }
@@ -41,4 +49,18 @@
   public void removeProjectEventsAsync(String projectName) {
     pool.submit(() -> eventsDb.removeProjectEvents(projectName));
   }
+
+  public void scheduleCleaningWith(int maxAge) {
+    pool.scheduleAtFixedRate(
+        () -> eventsDb.removeOldEvents(maxAge), getInitialDelay(), INTERVAL, TimeUnit.SECONDS);
+  }
+
+  private long getInitialDelay() {
+    ZonedDateTime now = ZonedDateTime.now(ZoneId.systemDefault());
+    ZonedDateTime next = now.withHour(HOUR).truncatedTo(ChronoUnit.HOURS);
+    if (now.isAfter(next)) {
+      next = next.plusDays(1);
+    }
+    return Duration.between(now, next).getSeconds();
+  }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLClient.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLClient.java
index e950dcd..2519eda 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLClient.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLClient.java
@@ -191,6 +191,7 @@
               TABLE_NAME,
               DATE_ENTRY,
               new Timestamp(System.currentTimeMillis() - MILLISECONDS.convert(maxAge, DAYS))));
+      log.info("Events older than {} days were removed from database", maxAge);
     } catch (SQLException e) {
       log.warn("Cannot remove old event entries from database", e);
     }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStore.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStore.java
index cdf104f..8e2ab52 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStore.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStore.java
@@ -93,6 +93,7 @@
   @Override
   public void start() {
     setUp();
+    eventsLogCleaner.scheduleCleaningWith(maxAge);
   }
 
   @Override
@@ -192,7 +193,6 @@
     if (online) {
       restoreEventsFromLocal();
     }
-    getEventsDb().removeOldEvents(maxAge);
   }
 
   private SQLClient getEventsDb() {
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 07654db..e019e8a 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -16,8 +16,8 @@
 
 plugin.@PLUGIN@.maxAge
 :    Specify the maximum allowed age in days of the entries in the database.
-     Any entries that are older than this value will be removed on server startup.
-     When not specified, the default value is 30 days.
+     Any entries that are older than this value will be removed every day at
+     23:00 hours. When not specified, the default value is 30 days.
 
 plugin.@PLUGIN@.returnLimit
 :    Specify the max amount of events that will be returned for each query.