diff --git a/Dockerfile b/Dockerfile
index 239e1977..a8d1f6cc 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -17,7 +17,7 @@ COPY ./run_tool.sh /app
COPY ./conf/default-config.json /app/conf/
COPY ./conf/*.xml /app/conf/
-RUN apk add --no-cache --upgrade libpng libcrypto3 libssl3 musl musl-utils gnutls && addgroup --gid 1100 uidusers && adduser -D -G uidusers --uid 1100 uid2-optout && mkdir -p /opt/uid2 && chmod 755 -R /opt/uid2 && mkdir -p /app && chmod 705 -R /app && mkdir -p /app/file-uploads && chmod 777 -R /app/file-uploads
+RUN apk add --no-cache --upgrade libpng libcrypto3 libssl3 musl musl-utils gnutls && addgroup --gid 1100 uidusers && adduser -D -G uidusers --uid 1100 uid2-optout && mkdir -p /opt/uid2 && chmod 755 -R /opt/uid2 && mkdir -p /app && chmod 705 -R /app && mkdir -p /app/file-uploads && chmod 777 -R /app/file-uploads && mkdir -p /app/pod_terminating && chmod 777 -R /app/pod_terminating
USER uid2-optout
CMD java \
diff --git a/pom.xml b/pom.xml
index 6c164f05..b4e444cd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.uid2
uid2-optout
- 4.10.3
+ 4.10.5-alpha-234-SNAPSHOT
uid2-optout
https://github.com/IABTechLab/uid2-optout
diff --git a/src/main/java/com/uid2/optout/Const.java b/src/main/java/com/uid2/optout/Const.java
index 24b9d082..f928f321 100644
--- a/src/main/java/com/uid2/optout/Const.java
+++ b/src/main/java/com/uid2/optout/Const.java
@@ -32,6 +32,7 @@ public static class Config extends com.uid2.shared.Const.Config {
public static final String OptOutSqsDeltaWindowSecondsProp = "optout_sqs_delta_window_seconds";
public static final String OptOutSqsMaxQueueSizeProp = "optout_sqs_max_queue_size";
public static final String AwsSqsEndpointProp = "aws_sqs_endpoint";
+ public static final String PodTerminationCheckInterval = "pod_termination_check_interval";
}
public static class Event {
diff --git a/src/main/java/com/uid2/optout/Main.java b/src/main/java/com/uid2/optout/Main.java
index 26b11b0e..9ca95f57 100644
--- a/src/main/java/com/uid2/optout/Main.java
+++ b/src/main/java/com/uid2/optout/Main.java
@@ -11,6 +11,8 @@
import com.uid2.shared.audit.UidInstanceIdProvider;
import com.uid2.shared.auth.RotatingOperatorKeyProvider;
import com.uid2.shared.cloud.*;
+import com.uid2.shared.health.HealthManager;
+import com.uid2.shared.health.PodTerminationMonitor;
import com.uid2.shared.jmx.AdminApi;
import com.uid2.shared.optout.OptOutCloudSync;
import com.uid2.shared.store.CloudPath;
@@ -65,6 +67,8 @@ public class Main {
public Main(Vertx vertx, JsonObject config) throws Exception {
this.vertx = vertx;
this.config = config;
+ HealthManager.instance.registerGenericComponent(new PodTerminationMonitor(
+ config.getInteger(Const.Config.PodTerminationCheckInterval, 3000)));
this.observeOnly = config.getBoolean(Const.Config.OptOutObserveOnlyProp);
if (this.observeOnly) {
LOGGER.warn("Running Observe ONLY mode: no producer, no sender");
diff --git a/src/test/java/com/uid2/optout/MainTest.java b/src/test/java/com/uid2/optout/MainTest.java
new file mode 100644
index 00000000..addf13b5
--- /dev/null
+++ b/src/test/java/com/uid2/optout/MainTest.java
@@ -0,0 +1,79 @@
+package com.uid2.optout;
+
+import com.uid2.shared.health.HealthManager;
+import com.uid2.shared.health.IHealthComponent;
+import com.uid2.shared.health.PodTerminationMonitor;
+import io.vertx.core.json.JsonObject;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+
+class MainTest {
+ @TempDir
+ Path tempDir;
+
+ private HealthManager originalHealthManager;
+ private CapturingHealthManager healthManager;
+
+ @BeforeEach
+ void setUp() {
+ originalHealthManager = HealthManager.instance;
+ healthManager = new CapturingHealthManager();
+ HealthManager.instance = healthManager;
+ }
+
+ @AfterEach
+ void tearDown() {
+ HealthManager.instance = originalHealthManager;
+ }
+
+ @Test
+ void constructorRegistersPodTerminationMonitorWithDefaultInterval() throws Exception {
+ new Main(null, createConfig());
+
+ PodTerminationMonitor monitor = assertInstanceOf(
+ PodTerminationMonitor.class, healthManager.registeredComponent);
+ assertEquals(3000L, getFileCheckInterval(monitor));
+ }
+
+ @Test
+ void constructorUsesConfiguredPodTerminationCheckInterval() throws Exception {
+ JsonObject config = createConfig()
+ .put(Const.Config.PodTerminationCheckInterval, 1250);
+
+ new Main(null, config);
+
+ PodTerminationMonitor monitor = assertInstanceOf(
+ PodTerminationMonitor.class, healthManager.registeredComponent);
+ assertEquals(1250L, getFileCheckInterval(monitor));
+ }
+
+ private JsonObject createConfig() throws Exception {
+ JsonObject config = new JsonObject(Files.readString(Path.of("conf/default-config.json")));
+ config.mergeIn(new JsonObject(Files.readString(Path.of("conf/local-config.json"))));
+ return config.put(Const.Config.OptOutDataDirProp, tempDir.toString());
+ }
+
+ private static long getFileCheckInterval(PodTerminationMonitor monitor) throws Exception {
+ var field = PodTerminationMonitor.class.getDeclaredField("fileCheckIntervalMs");
+ field.setAccessible(true);
+ return field.getLong(monitor);
+ }
+
+ private static class CapturingHealthManager extends HealthManager {
+ private IHealthComponent registeredComponent;
+
+ @Override
+ public synchronized T registerGenericComponent(T component) {
+ registeredComponent = component;
+ return component;
+ }
+ }
+}