From 70bd8ef0f82451c83529d8fd559057e273b6bcc5 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Tue, 21 Jul 2026 14:32:17 +0200 Subject: [PATCH 1/2] guard against stopping stats background threats --- .../main/java/com/cloud/server/StatsCollector.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/server/StatsCollector.java b/server/src/main/java/com/cloud/server/StatsCollector.java index 1e0138f7cf90..e50d47923f36 100644 --- a/server/src/main/java/com/cloud/server/StatsCollector.java +++ b/server/src/main/java/com/cloud/server/StatsCollector.java @@ -1286,13 +1286,21 @@ protected Point createInfluxDbPoint(Object metricsObject) { */ class VmStatsCleaner extends ManagedContextRunnable{ protected void runInContext() { - cleanUpVirtualMachineStats(); + try { + cleanUpVirtualMachineStats(); + } catch (CloudRuntimeException e) { + logger.error("Error trying to clean up VM stats", e); + } } } class VolumeStatsCleaner extends ManagedContextRunnable{ protected void runInContext() { - cleanUpVolumeStats(); + try { + cleanUpVolumeStats(); + } catch (CloudRuntimeException e) { + logger.error("Error trying to clean up Volume stats", e); + } } } From ce7a86683f95a5b8d414b4d484f2cc51fb907c86 Mon Sep 17 00:00:00 2001 From: Daan Hoogland Date: Tue, 21 Jul 2026 14:50:19 +0200 Subject: [PATCH 2/2] stats cleanup test --- .../com/cloud/server/StatsCollectorTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/server/src/test/java/com/cloud/server/StatsCollectorTest.java b/server/src/test/java/com/cloud/server/StatsCollectorTest.java index 3578e6948a45..46449a9cb6ed 100644 --- a/server/src/test/java/com/cloud/server/StatsCollectorTest.java +++ b/server/src/test/java/com/cloud/server/StatsCollectorTest.java @@ -335,6 +335,49 @@ public void cleanUpVirtualMachineStatsTestIsEnabled() { Mockito.verify(vmStatsDaoMock).removeAllByTimestampLessThan(Mockito.any(), Mockito.anyLong()); } + private void setVmDiskStatsMaxRetentionTimeValue(String value) { + StatsCollector.vmDiskStatsMaxRetentionTime = new ConfigKey("Advanced", Integer.class, "vm.disk.stats.max.retention.time", value, + "The maximum time (in minutes) for keeping Volume stats records in the database. The Volume stats cleanup process will be disabled if this is set to 0 or less than 0.", true); + } + + @Test + public void cleanUpVolumeStatsTestIsDisabled() { + setVmDiskStatsMaxRetentionTimeValue("0"); + + statsCollector.cleanUpVolumeStats(); + + Mockito.verify(volumeStatsDao, Mockito.never()).removeAllByTimestampLessThan(Mockito.any(), Mockito.anyLong()); + } + + @Test + public void cleanUpVolumeStatsTestIsEnabled() { + setVmDiskStatsMaxRetentionTimeValue("1"); + + statsCollector.cleanUpVolumeStats(); + + Mockito.verify(volumeStatsDao).removeAllByTimestampLessThan(Mockito.any(), Mockito.anyLong()); + } + + @Test + public void vmStatsCleanerTestCatchesCloudRuntimeExceptionAndKeepsRunning() { + Mockito.doThrow(new CloudRuntimeException("Communications link failure")).when(statsCollector).cleanUpVirtualMachineStats(); + StatsCollector.VmStatsCleaner vmStatsCleaner = statsCollector.new VmStatsCleaner(); + + vmStatsCleaner.run(); + + Mockito.verify(statsCollector).cleanUpVirtualMachineStats(); + } + + @Test + public void volumeStatsCleanerTestCatchesCloudRuntimeExceptionAndKeepsRunning() { + Mockito.doThrow(new CloudRuntimeException("Communications link failure")).when(statsCollector).cleanUpVolumeStats(); + StatsCollector.VolumeStatsCleaner volumeStatsCleaner = statsCollector.new VolumeStatsCleaner(); + + volumeStatsCleaner.run(); + + Mockito.verify(statsCollector).cleanUpVolumeStats(); + } + @Test public void persistVirtualMachineStatsTestPersistsSuccessfully() { statsCollector.msId = 1L;