From c6343db57da984530c57c425719d8f43a4eefb34 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Thu, 27 Jun 2024 09:21:22 +0200 Subject: [PATCH] feat: spread group folder expiry background job Signed-off-by: skjnldsv [skip ci] --- lib/AppInfo/Application.php | 5 +- lib/BackgroundJob/ExpireGroupVersions.php | 51 +++++++++++++++++++-- lib/Versions/GroupVersionsExpireManager.php | 7 +++ 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index f044d163a..317362b49 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -184,8 +184,11 @@ public function register(IRegistrationContext $context): void { $context->registerService(\OCA\GroupFolders\BackgroundJob\ExpireGroupVersions::class, function (IAppContainer $c) { if (interface_exists(\OCA\Files_Versions\Versions\IVersionBackend::class)) { return new ExpireGroupVersionsJob( + $c->get(ITimeFactory::class), $c->get(GroupVersionsExpireManager::class), - $c->get(ITimeFactory::class) + $c->get(IAppConfig::class), + $c->get(FolderManager::class), + $c->get(LoggerInterface::class), ); } diff --git a/lib/BackgroundJob/ExpireGroupVersions.php b/lib/BackgroundJob/ExpireGroupVersions.php index 7a13a3d1e..1fa214b60 100644 --- a/lib/BackgroundJob/ExpireGroupVersions.php +++ b/lib/BackgroundJob/ExpireGroupVersions.php @@ -24,15 +24,21 @@ namespace OCA\GroupFolders\BackgroundJob; +use OCA\GroupFolders\AppInfo\Application; +use OCA\GroupFolders\Folder\FolderManager; use OCA\GroupFolders\Versions\GroupVersionsExpireManager; use OCP\BackgroundJob\TimedJob; use OCP\AppFramework\Utility\ITimeFactory; class ExpireGroupVersions extends TimedJob { - private GroupVersionsExpireManager $expireManager; - - public function __construct(GroupVersionsExpireManager $expireManager, ITimeFactory $timeFactory) { - parent::__construct($timeFactory); + public function __construct( + ITimeFactory $time, + private GroupVersionsExpireManager $expireManager, + private IConfig $config, + private FolderManager $folderManager, + private LoggerInterface $logger, + ) { + parent::__construct($time); // Run once per hour $this->setInterval(60 * 60); @@ -42,7 +48,42 @@ public function __construct(GroupVersionsExpireManager $expireManager, ITimeFact $this->expireManager = $expireManager; } + /** + * Expiring groupfolder versions can be quite expensive. + * We need to limit the amount of folders we expire per run. + */ protected function run($argument) { - $this->expireManager->expireAll(); + $lastFolder = (int)$this->config->getAppValue(Application::APP_ID, 'cron_last_folder_index', '0'); + $folders = $this->folderManager->getAllFolders(); + + $folderCount = count($folders); + $currentRunHour = (int)date('G', $this->time->getTime()); + + // Calculate folders to process in the remaining hours, ensure at least one folder is processed + $toDo = max(1, (int)ceil(($folderCount - $lastFolder) / (24 - $currentRunHour))); + + // If there are no folders, we don't need to do anything + if ($folderCount === 0) { + $this->logger->debug('No folders to expire', ['app' => 'cron']); + return; + } + + // If we would go over the end of the list, wrap around + if ($lastFolder >= $folderCount) { + $lastFolder = 0; + } + + // Save the updated folder index BEFORE processing the folders + $this->config->setAppValue(Application::APP_ID, 'cron_last_folder_index', (string)($lastFolder + $toDo)); + + // Determine the set of folders to process + $folderSet = array_slice($folders, $lastFolder, $toDo); + $folderIDs = array_map(function ($folder) { + return $folder['id']; + }, $folderSet); + + // Log and start the expiration process + $this->logger->debug('Expiring versions for ' . count($folderSet) . ' folders', ['app' => 'cron', 'folders' => $folderIDs]); + $this->expireManager->expireFolders($folderSet); } } diff --git a/lib/Versions/GroupVersionsExpireManager.php b/lib/Versions/GroupVersionsExpireManager.php index 05d452eaa..2947098b0 100644 --- a/lib/Versions/GroupVersionsExpireManager.php +++ b/lib/Versions/GroupVersionsExpireManager.php @@ -61,6 +61,13 @@ public function expireAll(): void { } } + public function expireFolders(array $folders): void { + foreach ($folders as $folder) { + $this->emit(self::class, 'enterFolder', [$folder]); + $this->expireFolder($folder); + } + } + /** * @param array{id: int, mount_point: string, groups: array|array, quota: int, size: int, acl: bool} $folder */