From 67e4dd64e7906f0aab404acd95827ae4be8f76b4 Mon Sep 17 00:00:00 2001 From: fogelito Date: Sun, 3 Sep 2023 18:27:31 +0300 Subject: [PATCH] Cleanup --- Dockerfile | 1 + app/cli.php | 1 + bin/db-cleanup | 3 + src/Appwrite/Platform/Services/Tasks.php | 2 + src/Appwrite/Platform/Tasks/BackupCleanUp.php | 123 ++++++++++++++++++ 5 files changed, 130 insertions(+) create mode 100644 bin/db-cleanup create mode 100644 src/Appwrite/Platform/Tasks/BackupCleanUp.php diff --git a/Dockerfile b/Dockerfile index 2a810f07aa..be21c31c00 100755 --- a/Dockerfile +++ b/Dockerfile @@ -125,6 +125,7 @@ RUN chmod +x /usr/local/bin/doctor && \ chmod +x /usr/local/bin/maintenance && \ chmod +x /usr/local/bin/db-backup && \ chmod +x /usr/local/bin/db-restore && \ + chmod +x /usr/local/bin/db-cleanup && \ chmod +x /usr/local/bin/volume-sync && \ chmod +x /usr/local/bin/usage && \ chmod +x /usr/local/bin/install && \ diff --git a/app/cli.php b/app/cli.php index 2d12d69adb..4d1928a630 100644 --- a/app/cli.php +++ b/app/cli.php @@ -189,6 +189,7 @@ $cli ->error() ->inject('error') ->action(function (Throwable $error) { + var_dump($error); Console::error($error->getMessage()); }); diff --git a/bin/db-cleanup b/bin/db-cleanup new file mode 100644 index 0000000000..f017c5f874 --- /dev/null +++ b/bin/db-cleanup @@ -0,0 +1,3 @@ +#!/bin/sh + +php /usr/src/code/app/cli.php backup-cleanup $@ \ No newline at end of file diff --git a/src/Appwrite/Platform/Services/Tasks.php b/src/Appwrite/Platform/Services/Tasks.php index 436fa5eb8e..b744317e89 100644 --- a/src/Appwrite/Platform/Services/Tasks.php +++ b/src/Appwrite/Platform/Services/Tasks.php @@ -3,6 +3,7 @@ namespace Appwrite\Platform\Services; use Appwrite\Platform\Tasks\Backup; +use Appwrite\Platform\Tasks\BackupCleanUp; use Appwrite\Platform\Tasks\Restore; use Utopia\Platform\Service; use Appwrite\Platform\Tasks\Doctor; @@ -52,6 +53,7 @@ class Tasks extends Service ->addAction(PatchDeleteProjectCollections::getName(), new PatchDeleteProjectCollections()) ->addAction(Backup::getName(), new Backup()) ->addAction(Restore::getName(), new Restore()) + ->addAction(BackupCleanUp::getName(), new BackupCleanUp()) ; } } diff --git a/src/Appwrite/Platform/Tasks/BackupCleanUp.php b/src/Appwrite/Platform/Tasks/BackupCleanUp.php new file mode 100644 index 0000000000..a212074043 --- /dev/null +++ b/src/Appwrite/Platform/Tasks/BackupCleanUp.php @@ -0,0 +1,123 @@ +desc('Clean old backups') + ->param('database', null, new Text(20), 'Database name, for example db_fra1_01') + ->callback(fn(string $database) => $this->action($database)); + } + + public static function getName(): string + { + return 'backup-cleanup'; + } + + /** + * @throws Exception + */ + public function action(string $database): void + { + var_dump(App::getEnv('_APP_CONNECTIONS_BACKUPS_STORAGE')); + if (empty(App::getEnv('_APP_CONNECTIONS_BACKUPS_STORAGE'))) { + Console::error('Can\'t read ' . '_APP_CONNECTIONS_BACKUPS_STORAGE'); + Console::exit(); + } + + $this->database = $database; + + try { + $dsn = new DSN(App::getEnv('_APP_CONNECTIONS_BACKUPS_STORAGE', '')); + $this->s3 = new DOSpaces('/' . $database . '/full', $dsn->getUser(), $dsn->getPassword(), $dsn->getPath(), $dsn->getParam('region')); + } catch (\Exception $e) { + Console::error($e->getMessage()); + Console::exit(); + } + + Console::loop(function () { + $this->start(); + }, self::CLEANUP_INTERVAL_SECONDS); + } + + public function start(): void + { + $start = microtime(true); + self::log('--- Cleanup Start ' . date('Y-m-d H:i:s') . ' --- '); + $this->cleanLocalFiles(); + $this->cleanCloudFiles(); + self::log('--- Cleanup Finish ' . (microtime(true) - $start) . ' seconds --- ' . PHP_EOL . PHP_EOL); + } + + public function cleanLocalFiles() + { + self::log('cleanLocalFiles start'); + + $local = new Local(self::BACKUPS_PATH . '/' . $this->database . '/full'); + $folder = scandir($local->getRoot()); + $now = new \DateTime(); + if ($folder !== false) { + foreach ($folder as $item) { + if (str_ends_with($item, '.xbstream')) { + [$year, $month, $day, $hour, $minute, $second] = explode('_', basename($item, '.xbstream')); + $date = $year . '-' . $month . '-' . $day . ' ' . $hour . ':' . $minute . ':' . $second; + try { + $backupDate = new \DateTime($date); + $difference = $now->getTimestamp() - $backupDate->getTimestamp(); + if ($difference > self::CLEANUP_LOCAL_FILES_SECONDS) { + if ($this->s3->exists($this->s3->getRoot() . '/' . $item)) { + self::log('Deleting ' . $local->getPath($item)); + //unlink($local->getPath($item)); + } else { + Console::warning('Skipping delete file: ' . $local->getPath($item) . ' not found on cloud'); + } + } + } catch (Exception $e) { + Console::error('DateTime error: ' . $e->getMessage()); + } + } + } + } + } + + public function cleanCloudFiles() + { + self::log('cleanCloudFiles start'); + + // todo: how to scan a folder on cloud? + + if (!$this->s3->exists($this->s3->getRoot())) { + Console::error('Can\'t read s3 ' . $this->s3->getRoot()); + Console::exit(); + } + } + + public static function log(string $message): void + { + if (!empty($message)) { + Console::log(date('Y-m-d H:i:s') . ' ' . $message); + } + } +}