diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 04ef561fe6..3f29a0acf1 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -120,8 +120,7 @@ App::post('/v1/projects') 'database' => $pdo->getName() ])); - $cache = new Cache(new Redis($cache)); - $dbForProject = new Database(new MariaDB($pdo->getConnection()), $cache); + $dbForProject = DatabasePool::getDatabase($pdo->getConnection(), $cache); $dbForProject->setNamespace("_{$project->getInternalId()}"); $dbForProject->create(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); diff --git a/app/init.php b/app/init.php index 40d5370f38..2c71f9fc2a 100644 --- a/app/init.php +++ b/app/init.php @@ -866,25 +866,17 @@ App::setResource('dbForProject', function ($dbPool, $cache, Document $project) { if (empty($database)) { $database = $dbPool->getConsoleDB(); } - $pdo = $dbPool->getDBFromPool($database); - - $cache = new Cache(new RedisCache($cache)); - $database = new Database(new MariaDB($pdo->getConnection()), $cache); - $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); + $pdo = $dbPool->getPDOFromPool($database); + $database = DatabasePool::getDatabase($pdo->getConnection(), $cache); $database->setNamespace("_{$project->getInternalId()}"); - return $database; }, ['dbPool', 'cache', 'project']); App::setResource('dbForConsole', function ($dbPool, $cache) { $database = $dbPool->getConsoleDB(); - $pdo = $dbPool->getDBFromPool($database); - - $cache = new Cache(new RedisCache($cache)); - $database = new Database(new MariaDB($pdo->getConnection()), $cache); - $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); + $pdo = $dbPool->getPDOFromPool($database); + $database = DatabasePool::getDatabase($pdo->getConnection(), $cache); $database->setNamespace('_console'); - return $database; }, ['dbPool', 'cache']); diff --git a/app/realtime.php b/app/realtime.php index d1646c1426..6ea270c054 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -1,6 +1,7 @@ getConsoleDB(); - $pdo = $dbPool->getDBFromPool($database); - $cache = new Cache(new RedisCache($redis)); - $database = new Database(new MariaDB($pdo->getConnection()), $cache); - $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); + $pdo = $dbPool->getPDOFromPool($database); + $database = DatabasePool::getDatabase($pdo->getConnection(), $redis); $database->setNamespace("_console"); if ($projectId !== 'console') { $project = Authorization::skip(fn() => $database->getDocument('projects', $projectId)); $database = $project->getAttribute('database', ''); - $pdo = $dbPool->getDBFromPool($database); - $database = new Database(new MariaDB($pdo->getConnection()), $cache); - $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); + $pdo = $dbPool->getPDOFromPool($database); + $database = DatabasePool::getDatabase($pdo->getConnection(), $redis); $database->setNamespace("_{$project->getInternalId()}"); } @@ -478,18 +476,15 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re /** Get the console DB */ $database = $dbPool->getConsoleDB(); - $pdo = $dbPool->getDBFromPool($database); - $cache = new Cache(new RedisCache($redis)); - $database = new Database(new MariaDB($pdo->getConnection()), $cache); - $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); + $pdo = $dbPool->getPDOFromPool($database); + $database = DatabasePool::getDatabase($pdo->getConnection(), $redis); $database->setNamespace("_console"); if ($projectId !== 'console') { $project = Authorization::skip(fn() => $database->getDocument('projects', $projectId)); $database = $project->getAttribute('database', ''); - $pdo = $dbPool->getDBFromPool($database); - $database = new Database(new MariaDB($pdo->getConnection()), $cache); - $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); + $pdo = $dbPool->getPDOFromPool($database); + $database = DatabasePool::getDatabase($pdo->getConnection(), $redis); $database->setNamespace("_{$project->getInternalId()}"); } diff --git a/app/tasks/usage.php b/app/tasks/usage.php index c1d20b4d8d..6f145aef8d 100644 --- a/app/tasks/usage.php +++ b/app/tasks/usage.php @@ -6,7 +6,11 @@ use Appwrite\Stats\Usage; use Appwrite\Stats\UsageDB; use InfluxDB\Database as InfluxDatabase; use Utopia\App; +use Utopia\Cache\Adapter\Redis as RedisCache; +use Utopia\Cache\Cache; use Utopia\CLI\Console; +use Utopia\Database\Adapter\MariaDB; +use Utopia\Database\Database; use Utopia\Database\Validator\Authorization; use Utopia\Registry\Registry; use Utopia\Logger\Log; @@ -14,6 +18,34 @@ use Utopia\Logger\Log; Authorization::disable(); Authorization::setDefaultStatus(false); +function getDatabase(Registry &$register): Database +{ + $attempts = 0; + $dbPool = $register->get('dbPool'); + $redis = $register->get('cache'); + $database = $dbPool->getConsoleDB(); + do { + try { + $attempts++; + $database = $dbPool->getDB($database, $redis); + $database->setNamespace('_console'); + + if (!$database->exists($database->getDefaultDatabase(), 'projects')) { + throw new Exception('Projects collection not ready'); + } + break; // leave loop if successful + } catch (\Exception$e) { + Console::warning("Database not ready. Retrying connection ({$attempts})..."); + if ($attempts >= DATABASE_RECONNECT_MAX_ATTEMPTS) { + throw new \Exception('Failed to connect to database: ' . $e->getMessage()); + } + sleep(DATABASE_RECONNECT_SLEEP); + } + } while ($attempts < DATABASE_RECONNECT_MAX_ATTEMPTS); + + return $database; +} + function getInfluxDB(Registry &$register): InfluxDatabase { /** @var InfluxDB\Client $client */ @@ -82,9 +114,7 @@ $cli Console::success(APP_NAME . ' usage aggregation process v1 has started'); $interval = (int) App::getEnv('_APP_USAGE_AGGREGATION_INTERVAL', '30'); // 30 seconds (by default) - - $redis = $register->get('cache'); - $database = $register->get('dbPool')->getDB('console', $redis); + $database = getDatabase($register); $influxDB = getInfluxDB($register); $usage = new Usage($database, $influxDB, $logError); diff --git a/src/Appwrite/Database/DatabasePool.php b/src/Appwrite/Database/DatabasePool.php index 3854474dba..bb09c2df6a 100644 --- a/src/Appwrite/Database/DatabasePool.php +++ b/src/Appwrite/Database/DatabasePool.php @@ -6,7 +6,6 @@ use Appwrite\Database\PDO as DatabasePDO; use PDO; use Utopia\App; use Appwrite\DSN\DSN; -use Utopia\CLI\Console; use Utopia\Cache\Cache; use Swoole\Database\PDOProxy; use Utopia\Database\Database; @@ -14,7 +13,6 @@ use Appwrite\Extend\Exception; use Appwrite\Database\PDOPool; use Swoole\Database\PDOConfig; use Utopia\Database\Adapter\MariaDB; -use Utopia\Database\Validator\Authorization; use Utopia\Cache\Adapter\Redis as RedisCache; class DatabasePool @@ -86,7 +84,7 @@ class DatabasePool } /** - * Get a PDO instance by database name + * Get a single PDO instance by database name * * @param string $name * @@ -115,33 +113,6 @@ class DatabasePool return $pdo; } - // /** - // * Get the name of the database from the project ID - // * - // * @param string $projectID - // * - // * @return array - // */ - // private function getName(string $projectID, \Redis $redis): array - // { - // if ($projectID === 'console') { - // return [$this->consoleDB, 'console']; - // } - - // $pdo = $this->getPDO($this->consoleDB); - // $database = $this->getDatabase($pdo, $redis); - - // $namespace = "_console"; - // $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - // $database->setNamespace($namespace); - - // $project = Authorization::skip(fn() => $database->getDocument('projects', $projectID)); - // $internalID = $project->getInternalId(); - // $database = $project->getAttribute('database', ''); - - // return [$database, $internalID]; - // } - /** * Function to get a single PDO instance for a project * @@ -151,24 +122,9 @@ class DatabasePool */ public function getDB(string $database, ?\Redis $redis): ?Database { - /** Get a PDO instance using the databse name */ + /** Get a PDO instance using the database name */ $pdo = $this->getPDO($database); - $database = $this->getDatabase($pdo, $redis); - return $database; - } - - /** - * Get a database instance from a PDO and cache - * - * @param PDO|PDOProxy $pdo - * @param \Redis $redis - * - * @return Database - */ - private function getDatabase(PDO|PDOProxy $pdo, \Redis $redis): Database - { - $cache = new Cache(new RedisCache($redis)); - $database = new Database(new MariaDB($pdo), $cache); + $database = self::getDatabase($pdo, $redis); return $database; } @@ -179,36 +135,10 @@ class DatabasePool * * @return array */ - public function getDBFromPool(string $name): PDOWrapper + public function getPDOFromPool(string $name): PDOWrapper { - /** Get DB name from the console database */ - // [$name, $internalID] = $this->getName($projectID, $redis); $pool = $this->pools[$name] ?? throw new Exception("Database pool with name : $name not found. Check the value of _APP_DB_PROJECT in .env", 500); $pdo = $pool->get(); - - // $namespace = "_$internalID"; - // $attempts = 0; - // do { - // try { - // $attempts++; - // $pdo = $pool->get(); - // $database = $this->getDatabase($pdo, $redis); - // $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - // $database->setNamespace($namespace); - - // // if (!$database->exists($database->getDefaultDatabase(), 'metadata')) { - // // throw new Exception('Collection not ready'); - // // } - // break; // leave loop if successful - // } catch (\Exception $e) { - // Console::warning("Database not ready. Retrying connection ({$attempts})..."); - // if ($attempts >= DATABASE_RECONNECT_MAX_ATTEMPTS) { - // throw new \Exception('Failed to connect to database: ' . $e->getMessage()); - // } - // sleep(DATABASE_RECONNECT_SLEEP); - // } - // } while ($attempts < DATABASE_RECONNECT_MAX_ATTEMPTS); - return $pdo; } @@ -262,4 +192,46 @@ class DatabasePool return $this->consoleDB; } + + public static function wait() + { + // $namespace = "_$internalID"; + // $attempts = 0; + // do { + // try { + // $attempts++; + // $pdo = $pool->get(); + // $database = $this->getDatabase($pdo, $redis); + // $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); + // $database->setNamespace($namespace); + + // // if (!$database->exists($database->getDefaultDatabase(), 'metadata')) { + // // throw new Exception('Collection not ready'); + // // } + // break; // leave loop if successful + // } catch (\Exception $e) { + // Console::warning("Database not ready. Retrying connection ({$attempts})..."); + // if ($attempts >= DATABASE_RECONNECT_MAX_ATTEMPTS) { + // throw new \Exception('Failed to connect to database: ' . $e->getMessage()); + // } + // sleep(DATABASE_RECONNECT_SLEEP); + // } + // } while ($attempts < DATABASE_RECONNECT_MAX_ATTEMPTS); + } + + /** + * Get a database instance from a PDO and cache + * + * @param PDO|PDOProxy $pdo + * @param \Redis $redis + * + * @return Database + */ + public static function getDatabase(PDO|PDOProxy $pdo, \Redis $redis): Database + { + $cache = new Cache(new RedisCache($redis)); + $database = new Database(new MariaDB($pdo), $cache); + $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); + return $database; + } } diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index a7930b1cb5..df7863d593 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -180,7 +180,6 @@ abstract class Worker $dbForProject = $dbPool->getDB($database, $cache); $namespace = "_$internalId"; - $dbForProject->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); $dbForProject->setNamespace($namespace); return $dbForProject; @@ -202,7 +201,6 @@ abstract class Worker $dbForConsole = $dbPool->getDB($database, $cache); $namespace = "_console"; - $dbForConsole->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); $dbForConsole->setNamespace($namespace); return $dbForConsole;