Skip to content

Commit 5af7009

Browse files
artongebackportbot[bot]
authored andcommitted
feat(files_trashbin): Refactor expire background job to support parallel run
- Follow-up of #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 <[email protected]> [skip ci]
1 parent b8b7f51 commit 5af7009

2 files changed

Lines changed: 39 additions & 43 deletions

File tree

apps/files_trashbin/lib/BackgroundJob/ExpireTrash.php

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
use OCP\AppFramework\Utility\ITimeFactory;
3333
use OCP\BackgroundJob\TimedJob;
3434
use OCP\IAppConfig;
35+
use OCP\IUser;
3536
use OCP\IUserManager;
3637
use Psr\Log\LoggerInterface;
3738

@@ -45,8 +46,7 @@ public function __construct(
4546
ITimeFactory $time
4647
) {
4748
parent::__construct($time);
48-
// Run once per 30 minutes
49-
$this->setInterval(60 * 30);
49+
$this->setInterval(self::THIRTY_MINUTES);
5050
}
5151

5252
protected function run($argument) {
@@ -60,41 +60,44 @@ protected function run($argument) {
6060
return;
6161
}
6262

63-
$stopTime = time() + 60 * 30; // Stops after 30 minutes.
64-
$offset = $this->appConfig->getValueInt('files_trashbin', 'background_job_expire_trash_offset', 0);
65-
$users = $this->userManager->getSeenUsers($offset);
63+
$stopTime = time() + self::THIRTY_MINUTES;
6664

67-
foreach ($users as $user) {
68-
try {
65+
do {
66+
$this->appConfig->clearCache();
67+
$offset = $this->appConfig->getValueInt('files_trashbin', 'background_job_expire_trash_offset', 0);
68+
$this->appConfig->setValueInt('files_trashbin', 'background_job_expire_trash_offset', $offset + 10);
69+
70+
$users = $this->userManager->getSeenUsers($offset, 10);
71+
$count = 0;
72+
73+
foreach ($users as $user) {
6974
$uid = $user->getUID();
70-
if (!$this->setupFS($uid)) {
71-
continue;
75+
$count++;
76+
77+
try {
78+
if ($this->setupFS($user)) {
79+
$dirContent = Helper::getTrashFiles('/', $uid, 'mtime');
80+
Trashbin::deleteExpiredFiles($dirContent, $uid);
81+
}
82+
} catch (\Throwable $e) {
83+
$this->logger->error('Error while expiring trashbin for user ' . $uid, ['exception' => $e]);
84+
} finally {
85+
$this->setupManager->tearDown();
7286
}
73-
$dirContent = Helper::getTrashFiles('/', $uid, 'mtime');
74-
Trashbin::deleteExpiredFiles($dirContent, $uid);
75-
} catch (\Throwable $e) {
76-
$this->logger->error('Error while expiring trashbin for user ' . $user->getUID(), ['exception' => $e]);
7787
}
7888

79-
$offset++;
89+
} while (time() < $stopTime && $count === 10);
8090

81-
if ($stopTime < time()) {
82-
$this->appConfig->setValueInt('files_trashbin', 'background_job_expire_trash_offset', $offset);
83-
\OC_Util::tearDownFS();
84-
return;
85-
}
91+
if ($count < 10) {
92+
$this->appConfig->setValueInt('files_trashbin', 'background_job_expire_trash_offset', 0);
8693
}
87-
88-
$this->appConfig->setValueInt('files_trashbin', 'background_job_expire_trash_offset', 0);
89-
\OC_Util::tearDownFS();
9094
}
9195

9296
/**
9397
* Act on behalf on trash item owner
9498
*/
95-
protected function setupFS(string $user): bool {
96-
\OC_Util::tearDownFS();
97-
\OC_Util::setupFS($user);
99+
protected function setupFS(IUser $user): bool {
100+
$this->setupManager->setupForUser($user);
98101

99102
// Check if this user has a trashbin directory
100103
$view = new \OC\Files\View('/' . $user);

apps/files_trashbin/tests/BackgroundJob/ExpireTrashTest.php

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
namespace OCA\Files_Trashbin\Tests\BackgroundJob;
2727

28+
use OC\Files\SetupManager;
2829
use OCA\Files_Trashbin\BackgroundJob\ExpireTrash;
2930
use OCA\Files_Trashbin\Expiration;
3031
use OCP\AppFramework\Utility\ITimeFactory;
@@ -36,23 +37,14 @@
3637
use Test\TestCase;
3738

3839
class ExpireTrashTest extends TestCase {
39-
/** @var IAppConfig&MockObject */
40-
private $appConfig;
4140

42-
/** @var IUserManager&MockObject */
43-
private $userManager;
44-
45-
/** @var Expiration&MockObject */
46-
private $expiration;
47-
48-
/** @var IJobList&MockObject */
49-
private $jobList;
50-
51-
/** @var LoggerInterface&MockObject */
52-
private $logger;
53-
54-
/** @var ITimeFactory&MockObject */
55-
private $time;
41+
private IAppConfig&MockObject $appConfig;
42+
private IUserManager&MockObject $userManager;
43+
private Expiration&MockObject $expiration;
44+
private IJobList&MockObject $jobList;
45+
private LoggerInterface&MockObject $logger;
46+
private ITimeFactory&MockObject $time;
47+
private SetupManager&MockObject $setupManager;
5648

5749
protected function setUp(): void {
5850
parent::setUp();
@@ -62,6 +54,7 @@ protected function setUp(): void {
6254
$this->expiration = $this->createMock(Expiration::class);
6355
$this->jobList = $this->createMock(IJobList::class);
6456
$this->logger = $this->createMock(LoggerInterface::class);
57+
$this->setupManager = $this->createMock(SetupManager::class);
6558

6659
$this->time = $this->createMock(ITimeFactory::class);
6760
$this->time->method('getTime')
@@ -81,7 +74,7 @@ public function testConstructAndRun(): void {
8174
->with('files_trashbin', 'background_job_expire_trash_offset', 0)
8275
->willReturn(0);
8376

84-
$job = new ExpireTrash($this->appConfig, $this->userManager, $this->expiration, $this->logger, $this->time);
77+
$job = new ExpireTrash($this->appConfig, $this->userManager, $this->expiration, $this->logger, $this->setupManager, $this->time);
8578
$job->start($this->jobList);
8679
}
8780

@@ -92,7 +85,7 @@ public function testBackgroundJobDeactivated(): void {
9285
$this->expiration->expects($this->never())
9386
->method('getMaxAgeAsTimestamp');
9487

95-
$job = new ExpireTrash($this->appConfig, $this->userManager, $this->expiration, $this->logger, $this->time);
88+
$job = new ExpireTrash($this->appConfig, $this->userManager, $this->expiration, $this->logger, $this->setupManager, $this->time);
9689
$job->start($this->jobList);
9790
}
9891
}

0 commit comments

Comments
 (0)