feat: review comments
This commit is contained in:
parent
9e183f8994
commit
561e7b43e1
6 changed files with 132 additions and 91 deletions
|
@ -85,7 +85,7 @@ App::post('/v1/projects')
|
||||||
throw new Exception("'console' is a reserved project.", 400, Exception::PROJECT_RESERVED_PROJECT);
|
throw new Exception("'console' is a reserved project.", 400, Exception::PROJECT_RESERVED_PROJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
[$dbForProject, $returnDB, $dbName] = $dbPool->getAnyFromPool($cache);
|
[$dbForProject, $dbName] = $dbPool->getAnyFromPool($cache);
|
||||||
|
|
||||||
$project = $dbForConsole->createDocument('projects', new Document([
|
$project = $dbForConsole->createDocument('projects', new Document([
|
||||||
'$id' => $projectId,
|
'$id' => $projectId,
|
||||||
|
@ -161,8 +161,6 @@ App::post('/v1/projects')
|
||||||
$dbForProject->createCollection($key, $attributes, $indexes);
|
$dbForProject->createCollection($key, $attributes, $indexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
call_user_func($returnDB);
|
|
||||||
|
|
||||||
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
$response->setStatusCode(Response::STATUS_CODE_CREATED);
|
||||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||||
});
|
});
|
||||||
|
|
18
app/http.php
18
app/http.php
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
require_once __DIR__ . '/../vendor/autoload.php';
|
require_once __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use Appwrite\Database\DatabasePool;
|
||||||
use Appwrite\Utopia\Response;
|
use Appwrite\Utopia\Response;
|
||||||
use Swoole\Process;
|
use Swoole\Process;
|
||||||
use Swoole\Http\Server;
|
use Swoole\Http\Server;
|
||||||
|
@ -63,8 +64,9 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||||
App::setResource('cache', fn() => $redis);
|
App::setResource('cache', fn() => $redis);
|
||||||
|
|
||||||
$dbPool = $register->get('dbPool');
|
$dbPool = $register->get('dbPool');
|
||||||
[$dbForConsole, $returnDatabase] = $dbPool->getDBFromPool('console', $redis);
|
App::setResource('dbPool', fn() => $dbPool);
|
||||||
App::setResource('dbForConsole', fn() => $dbForConsole);
|
|
||||||
|
$dbForConsole = $app->getResource('dbForConsole'); /** @var Utopia\Database\Database $dbForConsole */
|
||||||
|
|
||||||
Console::success('[Setup] - Server database init started...');
|
Console::success('[Setup] - Server database init started...');
|
||||||
$collections = Config::getParam('collections', []); /** @var array $collections */
|
$collections = Config::getParam('collections', []); /** @var array $collections */
|
||||||
|
@ -196,7 +198,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||||
$dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
|
$dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
call_user_func($returnDatabase);
|
$dbPool->reset();
|
||||||
|
|
||||||
Console::success('[Setup] - Server database init completed...');
|
Console::success('[Setup] - Server database init completed...');
|
||||||
});
|
});
|
||||||
|
@ -236,13 +238,6 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||||
$dbPool = $register->get('dbPool');
|
$dbPool = $register->get('dbPool');
|
||||||
App::setResource('dbPool', fn() => $dbPool);
|
App::setResource('dbPool', fn() => $dbPool);
|
||||||
|
|
||||||
[$dbForConsole, $returnConsoleDB] = $dbPool->getDBFromPool('console', $redis);
|
|
||||||
App::setResource('dbForConsole', fn() => $dbForConsole);
|
|
||||||
|
|
||||||
$projectId = $request->getParam('project', $request->getHeader('x-appwrite-project', 'console'));
|
|
||||||
[$dbForProject, $returnProjectDB] = $dbPool->getDBFromPool($projectId, $redis);
|
|
||||||
App::setResource('dbForProject', fn() => $dbForProject);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Authorization::cleanRoles();
|
Authorization::cleanRoles();
|
||||||
Authorization::setRole('role:all');
|
Authorization::setRole('role:all');
|
||||||
|
@ -332,8 +327,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo
|
||||||
|
|
||||||
$swooleResponse->end(\json_encode($output));
|
$swooleResponse->end(\json_encode($output));
|
||||||
} finally {
|
} finally {
|
||||||
call_user_func($returnConsoleDB);
|
$dbPool->reset();
|
||||||
call_user_func($returnProjectDB);
|
|
||||||
|
|
||||||
/** @var RedisPool $redisPool */
|
/** @var RedisPool $redisPool */
|
||||||
$redisPool = $register->get('redisPool');
|
$redisPool = $register->get('redisPool');
|
||||||
|
|
37
app/init.php
37
app/init.php
|
@ -861,25 +861,30 @@ App::setResource('console', function () {
|
||||||
]);
|
]);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// App::setResource('dbForProject', function ($db, $cache, Document $project) {
|
App::setResource('dbForProject', function ($dbPool, $cache, Document $project) {
|
||||||
// $cache = new Cache(new RedisCache($cache));
|
$database = $project->getAttribute('database', '');
|
||||||
|
if (empty($database)) {
|
||||||
|
$database = $dbPool->getConsoleDB();
|
||||||
|
}
|
||||||
|
$pdo = $dbPool->getDBFromPool($database);
|
||||||
|
$cache = new Cache(new RedisCache($cache));
|
||||||
|
$database = new Database(new MariaDB($pdo), $cache);
|
||||||
|
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||||
|
$database->setNamespace("_{$project->getInternalId()}");
|
||||||
|
|
||||||
// $database = new Database(new MariaDB($db), $cache);
|
return $database;
|
||||||
// $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
}, ['dbPool', 'cache', 'project']);
|
||||||
// $database->setNamespace("_{$project->getInternalId()}");
|
|
||||||
|
|
||||||
// return $database;
|
App::setResource('dbForConsole', function ($dbPool, $cache) {
|
||||||
// }, ['db', 'cache', 'project']);
|
$database = $dbPool->getConsoleDB();
|
||||||
|
$pdo = $dbPool->getDBFromPool($database);
|
||||||
|
$cache = new Cache(new RedisCache($cache));
|
||||||
|
$database = new Database(new MariaDB($pdo), $cache);
|
||||||
|
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||||
|
$database->setNamespace('_console');
|
||||||
|
|
||||||
// App::setResource('dbForConsole', function ($dbPool, $cache) {
|
return $database;
|
||||||
// $cache = new Cache(new RedisCache($cache));
|
}, ['dbPool', 'cache']);
|
||||||
|
|
||||||
// $database = new Database(new MariaDB($db), $cache);
|
|
||||||
// $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
|
||||||
// $database->setNamespace('_console');
|
|
||||||
|
|
||||||
// return $database;
|
|
||||||
// }, ['dbPool', 'cache']);
|
|
||||||
|
|
||||||
App::setResource('deviceLocal', function () {
|
App::setResource('deviceLocal', function () {
|
||||||
return new Local();
|
return new Local();
|
||||||
|
|
|
@ -91,12 +91,12 @@ $server->error($logError);
|
||||||
function getDatabase(Registry &$register, string $projectID)
|
function getDatabase(Registry &$register, string $projectID)
|
||||||
{
|
{
|
||||||
$redis = $register->get('redisPool')->get();
|
$redis = $register->get('redisPool')->get();
|
||||||
[$database, $returnDatabase] = $register->get('dbPool')->getDBFromPool($projectID, $redis);
|
$database = $register->get('dbPool')->getDBFromPool($projectID, $redis);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
$database,
|
$database,
|
||||||
function () use ($register, $returnDatabase, $redis) {
|
function () use ($register, $redis) {
|
||||||
call_user_func($returnDatabase);
|
$register->get('dbPool')->reset();
|
||||||
$register->get('redisPool')->put($redis);
|
$register->get('redisPool')->put($redis);
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -345,7 +345,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||||
/** @var \Utopia\Database\Document $console */
|
/** @var \Utopia\Database\Document $console */
|
||||||
$console = $app->getResource('console');
|
$console = $app->getResource('console');
|
||||||
|
|
||||||
[$dbForConsole, $returnConsoleDB] = $dbPool->getDBFromPool('console', $redis);
|
$dbForConsole = $dbPool->getDBFromPool('console', $redis);
|
||||||
App::setResource('dbForConsole', fn() => $dbForConsole);
|
App::setResource('dbForConsole', fn() => $dbForConsole);
|
||||||
|
|
||||||
/** @var \Utopia\Database\Document $project */
|
/** @var \Utopia\Database\Document $project */
|
||||||
|
@ -358,7 +358,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||||
throw new Exception('Missing or unknown project ID', 1008);
|
throw new Exception('Missing or unknown project ID', 1008);
|
||||||
}
|
}
|
||||||
|
|
||||||
[$dbForProject, $returnProjectDB] = $dbPool->getDBFromPool($project->getId(), $redis);
|
$dbForProject = $dbPool->getDBFromPool($project->getId(), $redis);
|
||||||
App::setResource('dbForProject', fn() => $dbForProject);
|
App::setResource('dbForProject', fn() => $dbForProject);
|
||||||
|
|
||||||
/** @var \Utopia\Database\Document $user */
|
/** @var \Utopia\Database\Document $user */
|
||||||
|
@ -448,8 +448,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||||
/**
|
/**
|
||||||
* Put used PDO and Redis Connections back into their pools.
|
* Put used PDO and Redis Connections back into their pools.
|
||||||
*/
|
*/
|
||||||
call_user_func($returnConsoleDB);
|
$dbPool->reset();
|
||||||
call_user_func($returnProjectDB);
|
|
||||||
$register->get('redisPool')->put($redis);
|
$register->get('redisPool')->put($redis);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -463,7 +462,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||||
$redis = $register->get('redisPool')->get();
|
$redis = $register->get('redisPool')->get();
|
||||||
|
|
||||||
$dbPool = $register->get('dbPool');
|
$dbPool = $register->get('dbPool');
|
||||||
[$dbForProject, $returnProjectDB] = $dbPool->getDBFromPool($projectId, $redis);
|
$dbForProject = $dbPool->getDBFromPool($projectId, $redis);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Abuse Check
|
* Abuse Check
|
||||||
|
|
|
@ -7,10 +7,10 @@ use Utopia\App;
|
||||||
use Appwrite\DSN\DSN;
|
use Appwrite\DSN\DSN;
|
||||||
use Utopia\CLI\Console;
|
use Utopia\CLI\Console;
|
||||||
use Utopia\Cache\Cache;
|
use Utopia\Cache\Cache;
|
||||||
use Swoole\Database\PDOPool;
|
|
||||||
use Swoole\Database\PDOProxy;
|
use Swoole\Database\PDOProxy;
|
||||||
use Utopia\Database\Database;
|
use Utopia\Database\Database;
|
||||||
use Appwrite\Extend\Exception;
|
use Appwrite\Extend\Exception;
|
||||||
|
use Appwrite\Database\PDOPool;
|
||||||
use Swoole\Database\PDOConfig;
|
use Swoole\Database\PDOConfig;
|
||||||
use Utopia\Database\Adapter\MariaDB;
|
use Utopia\Database\Adapter\MariaDB;
|
||||||
use Utopia\Database\Validator\Authorization;
|
use Utopia\Database\Validator\Authorization;
|
||||||
|
@ -62,8 +62,7 @@ class DatabasePool
|
||||||
/** Create PDO pool instances for all the dsns */
|
/** Create PDO pool instances for all the dsns */
|
||||||
foreach ($this->dsns as $name => $dsn) {
|
foreach ($this->dsns as $name => $dsn) {
|
||||||
$dsn = new DSN($dsn);
|
$dsn = new DSN($dsn);
|
||||||
$pool = new PDOPool(
|
$pdoConfig = (new PDOConfig())
|
||||||
(new PDOConfig())
|
|
||||||
->withHost($dsn->getHost())
|
->withHost($dsn->getHost())
|
||||||
->withPort($dsn->getPort())
|
->withPort($dsn->getPort())
|
||||||
->withDbName($dsn->getDatabase())
|
->withDbName($dsn->getDatabase())
|
||||||
|
@ -77,9 +76,9 @@ class DatabasePool
|
||||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||||
PDO::ATTR_EMULATE_PREPARES => true,
|
PDO::ATTR_EMULATE_PREPARES => true,
|
||||||
PDO::ATTR_STRINGIFY_FETCHES => true
|
PDO::ATTR_STRINGIFY_FETCHES => true
|
||||||
]),
|
]);
|
||||||
64
|
|
||||||
);
|
$pool = new PDOPool($pdoConfig, 64);
|
||||||
|
|
||||||
$this->pools[$name] = $pool;
|
$this->pools[$name] = $pool;
|
||||||
}
|
}
|
||||||
|
@ -191,41 +190,37 @@ class DatabasePool
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getDBFromPool(string $projectID, \Redis $redis): array
|
public function getDBFromPool(string $name): PDO|PDOProxy
|
||||||
{
|
{
|
||||||
/** Get DB name from the console database */
|
/** Get DB name from the console database */
|
||||||
[$name, $internalID] = $this->getName($projectID, $redis);
|
// [$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);
|
$pool = $this->pools[$name] ?? throw new Exception("Database pool with name : $name not found. Check the value of _APP_DB_PROJECT in .env", 500);
|
||||||
|
|
||||||
$namespace = "_$internalID";
|
|
||||||
$attempts = 0;
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
$attempts++;
|
|
||||||
$pdo = $pool->get();
|
$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')) {
|
// $namespace = "_$internalID";
|
||||||
// throw new Exception('Collection not ready');
|
// $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());
|
||||||
// }
|
// }
|
||||||
break; // leave loop if successful
|
// sleep(DATABASE_RECONNECT_SLEEP);
|
||||||
} catch (\Exception $e) {
|
// }
|
||||||
Console::warning("Database not ready. Retrying connection ({$attempts})...");
|
// } while ($attempts < DATABASE_RECONNECT_MAX_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 [
|
return $pdo;
|
||||||
$database,
|
|
||||||
function () use ($pdo, $name) {
|
|
||||||
$this->put($pdo, $name);
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -261,13 +256,17 @@ class DatabasePool
|
||||||
|
|
||||||
return [
|
return [
|
||||||
$database,
|
$database,
|
||||||
function () use ($pdo, $name) {
|
|
||||||
$this->put($pdo, $name);
|
|
||||||
},
|
|
||||||
$name
|
$name
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function reset(): void
|
||||||
|
{
|
||||||
|
foreach ($this->pools as $pool) {
|
||||||
|
$pool->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a PDO instance back to its database pool
|
* Return a PDO instance back to its database pool
|
||||||
*
|
*
|
||||||
|
|
46
src/Appwrite/Database/PDOPool.php
Normal file
46
src/Appwrite/Database/PDOPool.php
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Appwrite\Database;
|
||||||
|
|
||||||
|
use Swoole\Database\PDOConfig;
|
||||||
|
use Swoole\Database\PDOPool as SwoolePDOPool;
|
||||||
|
|
||||||
|
|
||||||
|
class PDOPool
|
||||||
|
{
|
||||||
|
private array $activeConnections = [];
|
||||||
|
|
||||||
|
private SwoolePDOPool $pool;
|
||||||
|
|
||||||
|
public function __construct(PDOConfig $pdoConfig, int $size = SwoolePDOPool::DEFAULT_SIZE)
|
||||||
|
{
|
||||||
|
$this->pool = new SwoolePDOPool($pdoConfig, $size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActiveConnections()
|
||||||
|
{
|
||||||
|
return $this->activeConnections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get(float $timeout = -1)
|
||||||
|
{
|
||||||
|
$connection = $this->pool->get($timeout);
|
||||||
|
$this->activeConnections[] = $connection;
|
||||||
|
return $connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function put($connection): void
|
||||||
|
{
|
||||||
|
$this->pool->put($connection);
|
||||||
|
unset($this->activeConnections[array_search($connection, $this->activeConnections)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reset(): void
|
||||||
|
{
|
||||||
|
foreach($this->activeConnections as $connection) {
|
||||||
|
$this->pool->put($connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->activeConnections = [];
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue