diff --git a/README-CHANGES.xml b/README-CHANGES.xml index ff2a946d..fffd1aae 100644 --- a/README-CHANGES.xml +++ b/README-CHANGES.xml @@ -98,9 +98,14 @@ - + - + + + + + + diff --git a/com.io7m.idstore.server.service.maintenance/pom.xml b/com.io7m.idstore.server.service.maintenance/pom.xml index f31ee9ca..962beb0c 100644 --- a/com.io7m.idstore.server.service.maintenance/pom.xml +++ b/com.io7m.idstore.server.service.maintenance/pom.xml @@ -50,6 +50,10 @@ ${project.version} + + com.io7m.jmulticlose + com.io7m.jmulticlose.core + com.io7m.repetoir com.io7m.repetoir.core diff --git a/com.io7m.idstore.server.service.maintenance/src/main/java/com/io7m/idstore/server/service/maintenance/IdMaintenanceService.java b/com.io7m.idstore.server.service.maintenance/src/main/java/com/io7m/idstore/server/service/maintenance/IdMaintenanceService.java index a341b8d6..774476d8 100644 --- a/com.io7m.idstore.server.service.maintenance/src/main/java/com/io7m/idstore/server/service/maintenance/IdMaintenanceService.java +++ b/com.io7m.idstore.server.service.maintenance/src/main/java/com/io7m/idstore/server/service/maintenance/IdMaintenanceService.java @@ -24,15 +24,16 @@ import com.io7m.idstore.server.service.configuration.IdServerConfigurationService; import com.io7m.idstore.server.service.telemetry.api.IdServerTelemetryServiceType; import com.io7m.idstore.server.service.tls.IdTLSContextServiceType; +import com.io7m.jmulticlose.core.CloseableCollection; +import com.io7m.jmulticlose.core.CloseableCollectionType; +import com.io7m.jmulticlose.core.ClosingResourceFailedException; import com.io7m.repetoir.core.RPServiceType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.time.Duration; import java.util.Objects; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -46,42 +47,38 @@ public final class IdMaintenanceService private static final Logger LOG = LoggerFactory.getLogger(IdMaintenanceService.class); - private final ExecutorService executor; - private final IdServerClock clock; private final IdServerTelemetryServiceType telemetry; private final IdDatabaseType database; private final IdTLSContextServiceType tlsContexts; - private final IdServerConfigurationService configuration; private final AtomicBoolean closed; - private final CompletableFuture waitTLS; - private final CompletableFuture waitMaintenance; + private final ScheduledExecutorService tlsExecutor; + private final ScheduledExecutorService maintenanceExecutor; + private final CloseableCollectionType resources; private IdMaintenanceService( - final ExecutorService inExecutor, - final IdServerClock inClock, final IdServerTelemetryServiceType inTelemetry, final IdDatabaseType inDatabase, final IdTLSContextServiceType inTlsContexts, - final IdServerConfigurationService inConfiguration) + final ScheduledExecutorService inTlsExecutor, + final ScheduledExecutorService inMaintenanceExecutor) { - this.executor = - Objects.requireNonNull(inExecutor, "executor"); - this.clock = - Objects.requireNonNull(inClock, "clock"); + this.tlsExecutor = + Objects.requireNonNull(inTlsExecutor, "executor"); + this.maintenanceExecutor = + Objects.requireNonNull(inMaintenanceExecutor, "executor"); this.telemetry = Objects.requireNonNull(inTelemetry, "telemetry"); this.database = Objects.requireNonNull(inDatabase, "database"); this.tlsContexts = Objects.requireNonNull(inTlsContexts, "tlsContexts"); - this.configuration = - Objects.requireNonNull(inConfiguration, "configuration"); + + this.resources = CloseableCollection.create(); + this.resources.add(this.tlsExecutor); + this.resources.add(this.maintenanceExecutor); + this.closed = new AtomicBoolean(false); - this.waitTLS = - new CompletableFuture(); - this.waitMaintenance = - new CompletableFuture(); } /** @@ -109,92 +106,53 @@ public static IdMaintenanceService create( Objects.requireNonNull(telemetry, "telemetry"); Objects.requireNonNull(tlsContexts, "tlsContexts"); - final var executor = - Executors.newThreadPerTaskExecutor( - Thread.ofVirtual() - .name("com.io7m.cardant.maintenance-", 0L) - .factory() - ); + final var tlsExecutor = + Executors.newSingleThreadScheduledExecutor(r -> { + final var thread = new Thread(r); + thread.setName("com.io7m.cardant.maintenance.tls"); + thread.setDaemon(true); + return thread; + }); + + final var maintenanceExecutor = + Executors.newSingleThreadScheduledExecutor(r -> { + final var thread = new Thread(r); + thread.setName("com.io7m.cardant.maintenance.db"); + thread.setDaemon(true); + return thread; + }); final var maintenanceService = new IdMaintenanceService( - executor, - clock, telemetry, database, tlsContexts, - configuration + tlsExecutor, + maintenanceExecutor ); - executor.execute(maintenanceService::runTLSReloadTask); - executor.execute(maintenanceService::runMaintenanceTask); - return maintenanceService; - } - - /** - * A task that executes maintenance once when the service starts, and then - * again at every subsequent midnight. - */ - - private void runMaintenanceTask() - { - while (!this.closed.get()) { - try { - this.runMaintenance(); - } catch (final Exception e) { - // Not important. - } - - final var timeNow = - this.clock.now(); - final var timeNextMidnight = - timeNow.withHour(0) - .withMinute(0) - .withSecond(0) - .plusDays(1L); - - final var untilNext = - Duration.between(timeNow, timeNextMidnight); - - try { - this.waitMaintenance.get(untilNext.toSeconds(), TimeUnit.SECONDS); - } catch (final Exception e) { - break; - } - } - } - - /** - * A task that reloads TLS contexts at the specified reload interval. - */ - - private void runTLSReloadTask() - { final var reloadIntervalOpt = - this.configuration.configuration() + configuration.configuration() .maintenanceConfiguration() .tlsReloadInterval(); - if (reloadIntervalOpt.isEmpty()) { - return; - } + reloadIntervalOpt.ifPresent(duration -> { + tlsExecutor.scheduleWithFixedDelay( + maintenanceService::runTLSReload, + 0L, + duration.toMillis(), + TimeUnit.MILLISECONDS + ); + }); - final var reloadInterval = - reloadIntervalOpt.get(); + maintenanceExecutor.scheduleWithFixedDelay( + maintenanceService::runMaintenance, + 0L, + 24L, + TimeUnit.HOURS + ); - while (!this.closed.get()) { - try { - this.runTLSReload(); - } catch (final Exception e) { - // Not important. - } - - try { - this.waitTLS.get(reloadInterval.toSeconds(), TimeUnit.SECONDS); - } catch (final Exception e) { - break; - } - } + return maintenanceService; } private void runTLSReload() @@ -241,9 +199,11 @@ public String description() public void close() { if (this.closed.compareAndSet(false, true)) { - this.waitTLS.complete(null); - this.waitMaintenance.complete(null); - this.executor.close(); + try { + this.resources.close(); + } catch (final ClosingResourceFailedException e) { + // Nothing we can do about this. + } } } diff --git a/com.io7m.idstore.server.service.maintenance/src/main/java/module-info.java b/com.io7m.idstore.server.service.maintenance/src/main/java/module-info.java index 67b7a531..41961fd9 100644 --- a/com.io7m.idstore.server.service.maintenance/src/main/java/module-info.java +++ b/com.io7m.idstore.server.service.maintenance/src/main/java/module-info.java @@ -33,6 +33,7 @@ requires com.io7m.repetoir.core; requires io.opentelemetry.api; requires org.slf4j; + requires com.io7m.jmulticlose.core; exports com.io7m.idstore.server.service.maintenance; }