Skip to content

Commit

Permalink
Ensure maintenance runs
Browse files Browse the repository at this point in the history
This fixes an issue that was preventing maintenance (such as TLS
reloads) from running.

Fix: #243
  • Loading branch information
io7m committed Nov 8, 2024
1 parent 4c12083 commit 3fe3342
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 98 deletions.
9 changes: 7 additions & 2 deletions README-CHANGES.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,14 @@
</c:change>
</c:changes>
</c:release>
<c:release date="2024-11-03T20:16:12+00:00" is-open="true" ticket-system="com.github.io7m.idstore" version="2.0.2">
<c:release date="2024-11-08T12:14:00+00:00" is-open="true" ticket-system="com.github.io7m.idstore" version="2.0.2">
<c:changes>
<c:change date="2024-11-03T20:16:12+00:00" summary="Upgrade Temurin and Alpine in OCI containers."/>
<c:change date="2024-11-03T00:00:00+00:00" summary="Upgrade Temurin and Alpine in OCI containers."/>
<c:change date="2024-11-08T12:14:00+00:00" summary="Fix an issue that was preventing maintenance from running.">
<c:tickets>
<c:ticket id="243"/>
</c:tickets>
</c:change>
</c:changes>
</c:release>
</c:releases>
Expand Down
4 changes: 4 additions & 0 deletions com.io7m.idstore.server.service.maintenance/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>com.io7m.jmulticlose</groupId>
<artifactId>com.io7m.jmulticlose.core</artifactId>
</dependency>
<dependency>
<groupId>com.io7m.repetoir</groupId>
<artifactId>com.io7m.repetoir.core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<Void> waitTLS;
private final CompletableFuture<Void> waitMaintenance;
private final ScheduledExecutorService tlsExecutor;
private final ScheduledExecutorService maintenanceExecutor;
private final CloseableCollectionType<ClosingResourceFailedException> 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<Void>();
this.waitMaintenance =
new CompletableFuture<Void>();
}

/**
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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.
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit 3fe3342

Please sign in to comment.