delayed project deletion

This commit is contained in:
shimon
2025-06-04 10:42:19 +03:00
parent b47ab90665
commit e3e11c60dc
8 changed files with 152 additions and 10 deletions
+1
View File
@@ -67,6 +67,7 @@ RUN chmod +x /usr/local/bin/doctor && \
chmod +x /usr/local/bin/schedule-functions && \
chmod +x /usr/local/bin/schedule-executions && \
chmod +x /usr/local/bin/schedule-messages && \
chmod +x /usr/local/bin/schedule-projects && \
chmod +x /usr/local/bin/sdks && \
chmod +x /usr/local/bin/specs && \
chmod +x /usr/local/bin/ssl && \
+30 -1
View File
@@ -330,7 +330,29 @@ return [
'default' => null,
'array' => false,
'filters' => ['datetime'],
]
],
[
'$id' => ID::custom('scheduleId'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('_deletedAt'),
'type' => Database::VAR_DATETIME,
'format' => '',
'size' => Database::LENGTH_KEY,
'signed' => false,
'required' => false,
'default' => null,
'array' => false,
'filters' => ['datetime'],
],
],
'indexes' => [
[
@@ -382,6 +404,13 @@ return [
'lengths' => [],
'orders' => [],
],
[
'$id' => ID::custom('_key_deleted_at'),
'type' => Database::INDEX_KEY,
'attributes' => ['_deletedAt'],
'lengths' => [],
'orders' => [],
]
],
],
+27 -7
View File
@@ -19,6 +19,7 @@ use Appwrite\Utopia\Database\Validator\ProjectId;
use Appwrite\Utopia\Database\Validator\Queries\Projects;
use Appwrite\Utopia\Request;
use Appwrite\Utopia\Response;
use Cron\CronExpression;
use PHPMailer\PHPMailer\PHPMailer;
use Utopia\App;
use Utopia\Audit\Audit;
@@ -1171,14 +1172,33 @@ App::delete('/v1/projects/:projectId')
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$queueForDeletes
->setProject($project)
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($project);
$interval = (int)System::getEnv('_APP_PROJECTS_DELETE_EXPIRATION','3600');
$expiration = new \DateTime();
$expiration->add(new \DateInterval('PT' . $interval . 'S'));
$cronPattern = sprintf('%d %d %d %d *',
(int)$expiration->format('i'), // minute
(int)$expiration->format('G'), // hour
(int)$expiration->format('j'), // day of month
(int)$expiration->format('n') // month
);
if (!$dbForPlatform->deleteDocument('projects', $projectId)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Failed to remove project from DB');
}
$cronExpression = new CronExpression($cronPattern);
$scheduledAt = $cronExpression->getExpression();
$schedule = $dbForPlatform->createDocument('schedules', new Document([
'region' => $project->getAttribute('region'),
'resourceType' => 'project',
'resourceId' => $project->getId(),
'resourceInternalId' => $project->getInternalId(),
'resourceUpdatedAt' => DateTime::now(),
'projectId' => $project->getId(),
'schedule' => $scheduledAt,
'active' => true,
]));
$dbForPlatform->updateDocument('projects', $project->getId(), $project
->setAttribute('scheduleId', $schedule->getId()))
;
$response->noContent();
});
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
exec php /usr/src/code/app/cli.php schedule-projects $@
Generated
+2 -2
View File
@@ -8234,7 +8234,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
@@ -8258,5 +8258,5 @@
"platform-overrides": {
"php": "8.3"
},
"plugin-api-version": "2.6.0"
"plugin-api-version": "2.2.0"
}
+28
View File
@@ -932,6 +932,34 @@ services:
- _APP_DB_PASS
- _APP_DATABASE_SHARED_TABLES
appwrite-task-scheduler-projects:
entrypoint: schedule-projects
<<: *x-logging
container_name: appwrite-task-scheduler-projects
image: appwrite-dev
networks:
- appwrite
volumes:
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
depends_on:
- mariadb
- redis
environment:
- _APP_ENV
- _APP_WORKER_PER_CORE
- _APP_OPENSSL_KEY_V1
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_DB_HOST
- _APP_DB_PORT
- _APP_DB_SCHEMA
- _APP_DB_USER
- _APP_DB_PASS
- _APP_DATABASE_SHARED_TABLES
appwrite-assistant:
container_name: appwrite-assistant
image: appwrite/assistant:0.7.0
+2
View File
@@ -10,6 +10,7 @@ use Appwrite\Platform\Tasks\QueueRetry;
use Appwrite\Platform\Tasks\ScheduleExecutions;
use Appwrite\Platform\Tasks\ScheduleFunctions;
use Appwrite\Platform\Tasks\ScheduleMessages;
use Appwrite\Platform\Tasks\ScheduleProjects;
use Appwrite\Platform\Tasks\Screenshot;
use Appwrite\Platform\Tasks\SDKs;
use Appwrite\Platform\Tasks\Specs;
@@ -37,6 +38,7 @@ class Tasks extends Service
->addAction(ScheduleFunctions::getName(), new ScheduleFunctions())
->addAction(ScheduleExecutions::getName(), new ScheduleExecutions())
->addAction(ScheduleMessages::getName(), new ScheduleMessages())
->addAction(ScheduleProjects::getName(), new ScheduleProjects())
->addAction(Specs::getName(), new Specs())
->addAction(Upgrade::getName(), new Upgrade())
->addAction(Vars::getName(), new Vars())
@@ -0,0 +1,59 @@
<?php
namespace Appwrite\Platform\Tasks;
use Appwrite\Event\Delete;
use Utopia\Database\Database;
use Utopia\Pools\Group;
class ScheduleProjects extends ScheduleBase
{
public const UPDATE_TIMER = 3; // seconds
public const ENQUEUE_TIMER = 4; // seconds
public static function getName(): string
{
return 'schedule-projects';
}
public static function getSupportedResource(): string
{
return 'project';
}
public static function getCollectionId(): string
{
return 'projects';
}
protected function enqueueResources(Group $pools, Database $dbForPlatform, callable $getProjectDB): void
{
foreach ($this->schedules as $schedule) {
if (!$schedule['active']) {
continue;
}
$now = new \DateTime();
$scheduledAt = new \DateTime($schedule['schedule']);
if ($scheduledAt > $now) {
continue;
}
\go(function () use ($schedule, $scheduledAt, $dbForPlatform) {
(new Delete($this->publisher))
->setProject($schedule['project'])
->setType(DELETE_TYPE_DOCUMENT)
->setDocument($schedule['project'])
->trigger();
$dbForPlatform->deleteDocument('projects', $schedule['project']->getId());
$dbForPlatform->deleteDocument('schedules', $schedule['$id']);
$this->recordEnqueueDelay($scheduledAt);
unset($this->schedules[$schedule['$internalId']]);
});
}
}
}