aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis Chemineau <louis@chmn.me>2025-05-21 11:18:51 +0200
committerLouis Chemineau <louis@chmn.me>2025-05-21 11:42:20 +0200
commita58b3e94cb1603fe2b6aadfb91315b11b0fb18f0 (patch)
tree6da8f9eccd0b0fd5caedd85822ba69b37246daf2
parentda8bf4640d722220998517177e4568238cb67db9 (diff)
downloadnextcloud-server-backport/52825/stable31.tar.gz
nextcloud-server-backport/52825/stable31.zip
feat(files_trashbin): Refactor expire background job to support parallel runbackport/52825/stable31
- Follow-up of https://github.com/nextcloud/server/pull/51600 The original PR introduced the possibility to continue an `ExpireTrash` job by saving the offset. This was to prevent having to start over the whole user list when the job crashed or was killed. But on big instances, one process is not enough to go through all the users in a timely manner. Supporting parallel run allows covering more ground faster. This PR introduced this possibility. We are now storing the offset right away to allow another parallel job to pick up the task at that point. We are arbitrarily cutting the user list in chunk of 10 to not drastically overflow the 30 minutes time limit. Signed-off-by: Louis Chemineau <louis@chmn.me>
-rw-r--r--apps/files_trashbin/lib/BackgroundJob/ExpireTrash.php59
-rw-r--r--apps/files_trashbin/tests/BackgroundJob/ExpireTrashTest.php29
2 files changed, 44 insertions, 44 deletions
diff --git a/apps/files_trashbin/lib/BackgroundJob/ExpireTrash.php b/apps/files_trashbin/lib/BackgroundJob/ExpireTrash.php
index 5b97901b302..a918ab80850 100644
--- a/apps/files_trashbin/lib/BackgroundJob/ExpireTrash.php
+++ b/apps/files_trashbin/lib/BackgroundJob/ExpireTrash.php
@@ -6,6 +6,7 @@
*/
namespace OCA\Files_Trashbin\BackgroundJob;
+use OC\Files\SetupManager;
use OC\Files\View;
use OCA\Files_Trashbin\Expiration;
use OCA\Files_Trashbin\Helper;
@@ -13,20 +14,23 @@ use OCA\Files_Trashbin\Trashbin;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
use OCP\IAppConfig;
+use OCP\IUser;
use OCP\IUserManager;
use Psr\Log\LoggerInterface;
class ExpireTrash extends TimedJob {
+ private const THIRTY_MINUTES = 30 * 60;
+
public function __construct(
private IAppConfig $appConfig,
private IUserManager $userManager,
private Expiration $expiration,
private LoggerInterface $logger,
+ private SetupManager $setupManager,
ITimeFactory $time,
) {
parent::__construct($time);
- // Run once per 30 minutes
- $this->setInterval(60 * 30);
+ $this->setInterval(self::THIRTY_MINUTES);
}
protected function run($argument) {
@@ -40,44 +44,47 @@ class ExpireTrash extends TimedJob {
return;
}
- $stopTime = time() + 60 * 30; // Stops after 30 minutes.
- $offset = $this->appConfig->getValueInt('files_trashbin', 'background_job_expire_trash_offset', 0);
- $users = $this->userManager->getSeenUsers($offset);
+ $stopTime = time() + self::THIRTY_MINUTES;
+
+ do {
+ $this->appConfig->clearCache();
+ $offset = $this->appConfig->getValueInt('files_trashbin', 'background_job_expire_trash_offset', 0);
+ $this->appConfig->setValueInt('files_trashbin', 'background_job_expire_trash_offset', $offset + 10);
+
+ $users = $this->userManager->getSeenUsers($offset, 10);
+ $count = 0;
- foreach ($users as $user) {
- try {
+ foreach ($users as $user) {
$uid = $user->getUID();
- if (!$this->setupFS($uid)) {
- continue;
+ $count++;
+
+ try {
+ if ($this->setupFS($user)) {
+ $dirContent = Helper::getTrashFiles('/', $uid, 'mtime');
+ Trashbin::deleteExpiredFiles($dirContent, $uid);
+ }
+ } catch (\Throwable $e) {
+ $this->logger->error('Error while expiring trashbin for user ' . $uid, ['exception' => $e]);
+ } finally {
+ $this->setupManager->tearDown();
}
- $dirContent = Helper::getTrashFiles('/', $uid, 'mtime');
- Trashbin::deleteExpiredFiles($dirContent, $uid);
- } catch (\Throwable $e) {
- $this->logger->error('Error while expiring trashbin for user ' . $user->getUID(), ['exception' => $e]);
}
- $offset++;
+ } while (time() < $stopTime && $count === 10);
- if ($stopTime < time()) {
- $this->appConfig->setValueInt('files_trashbin', 'background_job_expire_trash_offset', $offset);
- \OC_Util::tearDownFS();
- return;
- }
+ if ($count < 10) {
+ $this->appConfig->setValueInt('files_trashbin', 'background_job_expire_trash_offset', 0);
}
-
- $this->appConfig->setValueInt('files_trashbin', 'background_job_expire_trash_offset', 0);
- \OC_Util::tearDownFS();
}
/**
* Act on behalf on trash item owner
*/
- protected function setupFS(string $user): bool {
- \OC_Util::tearDownFS();
- \OC_Util::setupFS($user);
+ protected function setupFS(IUser $user): bool {
+ $this->setupManager->setupForUser($user);
// Check if this user has a trashbin directory
- $view = new View('/' . $user);
+ $view = new View('/' . $user->getUID());
if (!$view->is_dir('/files_trashbin/files')) {
return false;
}
diff --git a/apps/files_trashbin/tests/BackgroundJob/ExpireTrashTest.php b/apps/files_trashbin/tests/BackgroundJob/ExpireTrashTest.php
index ee833e6beb8..c9811b80e92 100644
--- a/apps/files_trashbin/tests/BackgroundJob/ExpireTrashTest.php
+++ b/apps/files_trashbin/tests/BackgroundJob/ExpireTrashTest.php
@@ -7,6 +7,7 @@
namespace OCA\Files_Trashbin\Tests\BackgroundJob;
+use OC\Files\SetupManager;
use OCA\Files_Trashbin\BackgroundJob\ExpireTrash;
use OCA\Files_Trashbin\Expiration;
use OCP\AppFramework\Utility\ITimeFactory;
@@ -18,23 +19,14 @@ use Psr\Log\LoggerInterface;
use Test\TestCase;
class ExpireTrashTest extends TestCase {
- /** @var IAppConfig&MockObject */
- private $appConfig;
- /** @var IUserManager&MockObject */
- private $userManager;
-
- /** @var Expiration&MockObject */
- private $expiration;
-
- /** @var IJobList&MockObject */
- private $jobList;
-
- /** @var LoggerInterface&MockObject */
- private $logger;
-
- /** @var ITimeFactory&MockObject */
- private $time;
+ private IAppConfig&MockObject $appConfig;
+ private IUserManager&MockObject $userManager;
+ private Expiration&MockObject $expiration;
+ private IJobList&MockObject $jobList;
+ private LoggerInterface&MockObject $logger;
+ private ITimeFactory&MockObject $time;
+ private SetupManager&MockObject $setupManager;
protected function setUp(): void {
parent::setUp();
@@ -44,6 +36,7 @@ class ExpireTrashTest extends TestCase {
$this->expiration = $this->createMock(Expiration::class);
$this->jobList = $this->createMock(IJobList::class);
$this->logger = $this->createMock(LoggerInterface::class);
+ $this->setupManager = $this->createMock(SetupManager::class);
$this->time = $this->createMock(ITimeFactory::class);
$this->time->method('getTime')
@@ -63,7 +56,7 @@ class ExpireTrashTest extends TestCase {
->with('files_trashbin', 'background_job_expire_trash_offset', 0)
->willReturn(0);
- $job = new ExpireTrash($this->appConfig, $this->userManager, $this->expiration, $this->logger, $this->time);
+ $job = new ExpireTrash($this->appConfig, $this->userManager, $this->expiration, $this->logger, $this->setupManager, $this->time);
$job->start($this->jobList);
}
@@ -74,7 +67,7 @@ class ExpireTrashTest extends TestCase {
$this->expiration->expects($this->never())
->method('getMaxAgeAsTimestamp');
- $job = new ExpireTrash($this->appConfig, $this->userManager, $this->expiration, $this->logger, $this->time);
+ $job = new ExpireTrash($this->appConfig, $this->userManager, $this->expiration, $this->logger, $this->setupManager, $this->time);
$job->start($this->jobList);
}
}