diff --git a/config/global.ini.php b/config/global.ini.php index ca995501a5d..52b5fbe8a83 100644 --- a/config/global.ini.php +++ b/config/global.ini.php @@ -1154,6 +1154,10 @@ delete_reports_keep_range_reports = 0 delete_reports_keep_segment_reports = 0 +[ArchivingMetrics] +; retention_days - delete archiving metrics older than this many days. Set to 0 to disable cleanup. +retention_days = 180 + [mail] defaultHostnameIfEmpty = defaultHostnameIfEmpty.example.org ; default Email @hostname, if current host can't be read from system variables transport = ; smtp (using the configuration below) or empty (using built-in mail() function) diff --git a/plugins/ArchivingMetrics/Tasks.php b/plugins/ArchivingMetrics/Tasks.php new file mode 100644 index 00000000000..dc702be830e --- /dev/null +++ b/plugins/ArchivingMetrics/Tasks.php @@ -0,0 +1,58 @@ +weekly('purgeOldMetrics'); + $this->monthly('purgeMetricsForDeletedSites'); + } + + /** + * To test execute the following command: + * `./console core:run-scheduled-tasks --force "Piwik\Plugins\ArchivingMetrics\Tasks.purgeOldMetrics"` + */ + public function purgeOldMetrics() + { + $retentionDays = $this->getRetentionDays(); + if ($retentionDays <= 0) { + return; + } + + $cutoff = Date::now()->subDay($retentionDays)->getDatetime(); + $table = Common::prefixTable('archiving_metrics'); + Db::query("DELETE FROM {$table} WHERE ts_started < ?", [$cutoff]); + } + + public function purgeMetricsForDeletedSites() + { + $siteTable = Common::prefixTable('site'); + $table = Common::prefixTable('archiving_metrics'); + Db::query("DELETE a FROM {$table} a LEFT JOIN {$siteTable} s ON a.idsite = s.idsite WHERE s.idsite IS NULL"); + } + + private function getRetentionDays(): int + { + $config = Config::getInstance(); + $retentionDays = $config->ArchivingMetrics['retention_days'] ?? self::DEFAULT_RETENTION_DAYS; + return max(0, (int) $retentionDays); + } +} diff --git a/plugins/ArchivingMetrics/tests/Integration/TasksTest.php b/plugins/ArchivingMetrics/tests/Integration/TasksTest.php new file mode 100644 index 00000000000..0dc3791a344 --- /dev/null +++ b/plugins/ArchivingMetrics/tests/Integration/TasksTest.php @@ -0,0 +1,92 @@ +ArchivingMetrics = ['retention_days' => 30]; + + $this->insertRow(Date::now()->subDay(31)->getDatetime()); + $this->insertRow(Date::now()->subDay(5)->getDatetime()); + + $task = new Tasks(); + $task->purgeOldMetrics(); + + $count = (int) Db::fetchOne('SELECT COUNT(*) FROM ' . Common::prefixTable('archiving_metrics')); + $this->assertSame(1, $count); + } + + public function testPurgeOldMetricsDisabledKeepsRows(): void + { + $config = Config::getInstance(); + $config->ArchivingMetrics = ['retention_days' => 0]; + + $this->insertRow(Date::now()->subDay(400)->getDatetime()); + + $task = new Tasks(); + $task->purgeOldMetrics(); + + $count = (int) Db::fetchOne('SELECT COUNT(*) FROM ' . Common::prefixTable('archiving_metrics')); + $this->assertSame(1, $count); + } + + public function testPurgeMetricsForDeletedSitesRemovesOrphanedRows(): void + { + $idSite = Fixture::createWebsite('2024-01-01 00:00:00'); + + $this->insertRow(Date::now()->subDay(5)->getDatetime(), $idSite); + $this->insertRow(Date::now()->subDay(5)->getDatetime(), 9999); + + $task = new Tasks(); + $task->purgeMetricsForDeletedSites(); + + $count = (int) Db::fetchOne('SELECT COUNT(*) FROM ' . Common::prefixTable('archiving_metrics')); + $this->assertSame(1, $count); + } + + private function insertRow(string $tsStarted, int $idSite = 1): void + { + $table = Common::prefixTable('archiving_metrics'); + Db::query( + "INSERT INTO {$table} (idarchive, idsite, archive_name, date1, date2, period, ts_started, ts_finished, total_time, total_time_exclusive) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + [ + 1, + $idSite, + 'done', + '2025-01-01', + '2025-01-01', + 1, + $tsStarted, + $tsStarted, + 123, + 100, + ] + ); + } +}