diff --git a/appinfo/info.xml b/appinfo/info.xml
index 6df3cfd..c496150 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -6,7 +6,7 @@
NextMagentaCloud business functions for customer tariff evaluation
This app contains business logic to evaluate provisoning info paased in
as set of openid claim-like attributes
- 1.0.0-nmc
+ 1.1.0
agpl
Bernd Rederlechner
NextMagentaCloudProvisioning
diff --git a/lib/Db/UserQueries.php b/lib/Db/UserQueries.php
index e709c27..9b0cf66 100644
--- a/lib/Db/UserQueries.php
+++ b/lib/Db/UserQueries.php
@@ -45,14 +45,14 @@ public function __construct(IDBConnection $db) {
*/
public function findDeletions(\DateTime $refDate, $limit = null, $offset = null): array {
$refTs = $refDate->getTimestamp();
-
+
$qb = $this->db->getQueryBuilder();
- //->andWhere($qb->expr()->lt('configvalue', $qb->createNamedParameter($refTs, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT))
$qb->select('userid')
->from('preferences')
->where($qb->expr()->eq('appid', $qb->createNamedParameter(Application::APP_ID)))
->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter('deletion')))
->andWhere($qb->expr()->lt('configvalue', $qb->createNamedParameter($refTs, IQueryBuilder::PARAM_INT)))
+ ->orderBy('configvalue', 'ASC') // oldest first
->setMaxResults($limit)
->setFirstResult($offset);
diff --git a/lib/User/UserAccountDeletionJob.php b/lib/User/UserAccountDeletionJob.php
index e7af604..6829df9 100644
--- a/lib/User/UserAccountDeletionJob.php
+++ b/lib/User/UserAccountDeletionJob.php
@@ -5,78 +5,99 @@
use OCA\NextMagentaCloudProvisioning\Db\UserQueries;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
-use OCP\IConfig;
-
use OCP\ILogger;
-
-//use OCP\BackgroundJob\QueuedJob;
use OCP\IUserManager;
+use Psr\Log\LoggerInterface;
-//class SlupCircuitBootJob extends QueuedJob {
class UserAccountDeletionJob extends TimedJob {
public const CIRCUIT_BOOT_DELAY = 300;
- /** @var ILogger */
+ /** @var LoggerInterface */
private $logger;
- /** @var IConfig */
- private $config;
-
/** @var UserQueries */
private $userQueries;
/** @var IUserManager */
private $userManager;
-
public function __construct(ITimeFactory $timeFactory,
- ILogger $logger,
- IConfig $config,
+ LoggerInterface $logger,
UserQueries $userQueries,
IUserManager $userManager) {
parent::__construct($timeFactory);
- $this->logger = $logger; // this is inconsistent with TimedJob
- $this->config = $config;
+ $this->logger = $logger;
$this->userQueries = $userQueries;
$this->userManager = $userManager;
-
- //$destTimeString = $this->config->getAppValue('nmcprovisioning', 'deletionjobtime', '04:00:00');
- //$destTime = new \DateTime($destTimeString);
-
- //$diff = $destTime->getTimestamp() - $this->getLastRun();
- // negative diff means that the lastRun date lies before the plan date today, so run today
- // otherwise tomorrow
- $this->setInterval(3 * 60 * 60);
}
- // Method re-declared public for unittest purpose
- public function getInterval() : int {
+ public function getInterval(): int {
return $this->interval;
}
public function run($arguments) {
$this->logger->info("User account deletion job started");
-
- // TODO: chunk deletion loop with offset, limit
- // if the set of deletion users is too big
- $refTime = new \DateTime(); // NOW
- $expiredUids = $this->userQueries->findDeletions($refTime);
- $this->logger->info(\count($expiredUids) . " withdrawn user with expired retention period.");
- foreach ($expiredUids as $uid) {
- try {
- $user = $this->userManager->get($uid);
- $this->logger->info("Deleting " . $uid);
- $user->delete();
- $this->logger->info(\count($uid) . " deleted");
- } catch (\Throwable $e) {
- $this->logger->logException($e, [
- 'message' => $uid . ': Deletion failed with ' . $e->getMessage(),
- 'level' => ILogger::ERROR,
- 'app' => 'nmcprovisioning'
- ]);
+
+ $startTime = time(); // start time of job
+ $maxExecutionTime = 10800; // max. job time (3 hours)
+ $maxDeletionTimePerUser = 1800; // max. time per user (30 minutes)
+
+ $refTime = new \DateTime(); // find deletions older than current time
+ $limit = 10; // number of users per batch
+ $offset = 0; // start offset
+
+ while (time() - $startTime < $maxExecutionTime) {
+ $expiredUids = $this->userQueries->findDeletions($refTime, $limit, $offset);
+
+ if (empty($expiredUids)) {
+ $this->logger->info("No more users to delete, exiting job.");
+ break; // No more users to delete
}
+
+ $this->logger->info(\count($expiredUids) . " users found for deletion in this batch.");
+
+ foreach ($expiredUids as $uid) {
+ // cancel if the runtime has exceeded 3 hours
+ if (time() - $startTime > $maxExecutionTime) {
+ $this->logger->info("User account deletion job stopped after 3 hours.");
+ return;
+ }
+
+ try {
+ $user = $this->userManager->get($uid);
+ if (!$user) {
+ $this->logger->warning("User $uid not found, skipping.");
+ continue;
+ }
+
+ $this->logger->info("Deleting " . $uid);
+ $startDeletionTime = time(); // start time for this user
+
+ // delete user
+ $user->delete();
+
+ // if deletion takes longer than 30 minutes, cancel
+
+ if (time() - $startDeletionTime > $maxDeletionTimePerUser) {
+ $this->logger->warning("User $uid deletion took too long, skipping.");
+ continue;
+ }
+
+ $this->logger->info("User $uid deleted successfully.");
+
+ } catch (\Throwable $e) {
+ $this->logger->logException($e, [
+ 'message' => "Deletion failed for $uid: " . $e->getMessage(),
+ 'level' => ILogger::ERROR,
+ 'app' => 'nmcprovisioning'
+ ]);
+ continue; // jump to the next user in case of errors
+ }
+ }
+
+ $offset += $limit; // jump to next batch
}
-
+
$this->logger->info("User account deletion job ended");
}
}
diff --git a/tests/unit/UserAccounctDeletionJobTest.php b/tests/unit/UserAccounctDeletionJobTest.php
index ddc6fab..8f8a646 100644
--- a/tests/unit/UserAccounctDeletionJobTest.php
+++ b/tests/unit/UserAccounctDeletionJobTest.php
@@ -8,14 +8,11 @@
use OCA\NextMagentaCloudProvisioning\Db\UserQueries;
use OCA\NextMagentaCloudProvisioning\User\UserAccountDeletionJob;
use OCP\AppFramework\Utility\ITimeFactory;
-
use OCP\IConfig;
-
-use OCP\ILogger;
use OCP\IUser;
-
use OCP\IUserManager;
use PHPUnit\Framework\TestCase;
+use Psr\Log\LoggerInterface;
class UserAccountDeletionJobTest extends TestCase {
public function setUp(): void {
@@ -25,7 +22,7 @@ public function setUp(): void {
$this->userQueries = $this->createMock(UserQueries::class);
$this->userManager = $this->getMockForAbstractClass(IUserManager::class);
$this->job = new UserAccountDeletionJob($this->app->getContainer()->get(ITimeFactory::class),
- $this->app->getContainer()->get(ILogger::class),
+ $this->app->getContainer()->get(LoggerInterface::class),
$this->config,
$this->userQueries,
$this->userManager);
@@ -51,7 +48,7 @@ public function setUp(): void {
// ->with($this->equalTo('nmcprovisioning'), $this->equalTo('deletionjobtime'))
// ->willReturn('05:00:00');
- // $refTime = new \DateTime("11:23:33");
+ // $refTime = new \DateTime("11:23:33");Mura
// $interval = $this->job->computeDestinationInterval($refTime);
// $this->assertEquals(27 + 36*60 + 17*3600 , $interval);