desc('Migrate Appwrite to new version') /** @TODO APP_VERSION_STABLE needs to be defined */ ->param('version', APP_VERSION_STABLE, new Text(8), 'Version to migrate to.', true) ->inject('cache') ->inject('dbForConsole') ->inject('getProjectDB') ->inject('register') ->inject('authorization') ->inject('console') ->callback(function ($version, $dbForConsole, $getProjectDB, Registry $register, Authorization $authorization, Document $console) { \Co\run(function () use ($version, $dbForConsole, $getProjectDB, $register, $authorization, $console) { $this->action($version, $dbForConsole, $getProjectDB, $register, $authorization, $console); }); }); } private function clearProjectsCache(Document $project) { try { $iterator = null; do { $pattern = "default-cache-_{$project->getInternalId()}:*"; $keys = $this->redis->scan($iterator, $pattern, 1000); if ($keys !== false) { foreach ($keys as $key) { $this->redis->del($key); } } } while ($iterator > 0); } catch (\Throwable $th) { Console::error('Failed to clear project ("' . $project->getId() . '") cache with error: ' . $th->getMessage()); } } public function action(string $version, Database $dbForConsole, callable $getProjectDB, Registry $register, Authorization $auth, Document $console) { $auth->disable(); if (!array_key_exists($version, Migration::$versions)) { Console::error("Version {$version} not found."); Console::exit(1); return; } $this->redis = new Redis(); $this->redis->connect( System::getEnv('_APP_REDIS_HOST', null), System::getEnv('_APP_REDIS_PORT', 6379), 3, null, 10 ); Console::success('Starting Data Migration to version ' . $version); $limit = 30; $sum = 30; $offset = 0; /** * @var \Utopia\Database\Document[] $projects */ $projects = [$console]; $count = 0; try { $totalProjects = $dbForConsole->count('projects') + 1; } catch (\Throwable $th) { $dbForConsole->setNamespace('_console'); $totalProjects = $dbForConsole->count('projects') + 1; } $class = 'Appwrite\\Migration\\Version\\' . Migration::$versions[$version]; /** @var Migration $migration */ $migration = new $class($auth, ); while (!empty($projects)) { foreach ($projects as $project) { /** * Skip user projects with id 'console' */ if ($project->getId() === 'console' && $project->getInternalId() !== 'console') { continue; } $this->clearProjectsCache($project); try { // TODO: Iterate through all project DBs /** @var Database $projectDB */ $projectDB = $getProjectDB($project); $projectDB->disableValidation(); $migration ->setProject($project, $projectDB, $dbForConsole) ->setPDO($register->get('db', true)) ->execute(); } catch (\Throwable $th) { Console::error('Failed to update project ("' . $project->getId() . '") version with error: ' . $th->getMessage()); throw $th; } $this->clearProjectsCache($project); } $sum = \count($projects); $projects = $dbForConsole->find('projects', [Query::limit($limit), Query::offset($offset)]); $offset = $offset + $limit; $count = $count + $sum; Console::log('Migrated ' . $count . '/' . $totalProjects . ' projects...'); } Console::success('Data Migration Completed'); } }