From 5af7dc943fe3637529250230b149342df91493b5 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 8 Oct 2022 08:42:53 +0300 Subject: [PATCH 01/36] Renamed DatabasePool to Pools --- app/controllers/api/projects.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 2a7063a97f..7b6d0544d2 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -2,7 +2,7 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\Validator\Password; -use Appwrite\Database\DatabasePool; +use Appwrite\Database\Pools; use Appwrite\Event\Certificate; use Appwrite\Event\Delete; use Appwrite\Event\Validator\Event; @@ -68,7 +68,7 @@ App::post('/v1/projects') ->inject('dbForConsole') ->inject('cache') ->inject('dbPool') - ->action(function (string $projectId, string $name, string $teamId, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, \Redis $cache, DatabasePool $dbPool) { + ->action(function (string $projectId, string $name, string $teamId, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, \Redis $cache, Pools $dbPool) { $team = $dbForConsole->getDocument('teams', $teamId); From 26b1a94d22c9b88af7cf5c863559c86e87682367 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 8 Oct 2022 08:43:02 +0300 Subject: [PATCH 02/36] Renamed DatabasePool to Pools --- app/http.php | 1 - app/init.php | 4 +-- .../Database/{DatabasePool.php => Pools.php} | 36 ++++++++----------- 3 files changed, 17 insertions(+), 24 deletions(-) rename src/Appwrite/Database/{DatabasePool.php => Pools.php} (88%) diff --git a/app/http.php b/app/http.php index 86efc60b8d..691c2249b2 100644 --- a/app/http.php +++ b/app/http.php @@ -2,7 +2,6 @@ require_once __DIR__ . '/../vendor/autoload.php'; -use Appwrite\Database\DatabasePool; use Appwrite\Utopia\Response; use Swoole\Process; use Swoole\Http\Server; diff --git a/app/init.php b/app/init.php index 705a47c0ec..baa35bec4e 100644 --- a/app/init.php +++ b/app/init.php @@ -49,7 +49,7 @@ use MaxMind\Db\Reader; use PHPMailer\PHPMailer\PHPMailer; use Utopia\Database\Document; use Utopia\Database\Database; -use Appwrite\Database\DatabasePool; +use Appwrite\Database\Pools; use Appwrite\Event\Delete; use Utopia\Database\Validator\Structure; use Utopia\Database\Validator\Authorization; @@ -475,7 +475,7 @@ $register->set('dbPool', function () { $projectDBs[$name] = $dsn; } - $pool = new DatabasePool($consoleDBs, $projectDBs); + $pool = new Pools($consoleDBs, $projectDBs); return $pool; }); diff --git a/src/Appwrite/Database/DatabasePool.php b/src/Appwrite/Database/Pools.php similarity index 88% rename from src/Appwrite/Database/DatabasePool.php rename to src/Appwrite/Database/Pools.php index 5e04c47984..756a99310a 100644 --- a/src/Appwrite/Database/DatabasePool.php +++ b/src/Appwrite/Database/Pools.php @@ -2,22 +2,16 @@ namespace Appwrite\Database; -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; 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 +class Pools { /** * @var array @@ -64,20 +58,20 @@ class DatabasePool foreach ($this->dsns as $name => $dsn) { $dsn = new DSN($dsn); $pdoConfig = (new PDOConfig()) - ->withHost($dsn->getHost()) - ->withPort($dsn->getPort()) - ->withDbName($dsn->getDatabase()) - ->withCharset('utf8mb4') - ->withUsername($dsn->getUser()) - ->withPassword($dsn->getPassword()) - ->withOptions([ - PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed - PDO::ATTR_TIMEOUT => 3, // Seconds - PDO::ATTR_PERSISTENT => true, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => true, - PDO::ATTR_STRINGIFY_FETCHES => true - ]); + ->withHost($dsn->getHost()) + ->withPort($dsn->getPort()) + ->withDbName($dsn->getDatabase()) + ->withCharset('utf8mb4') + ->withUsername($dsn->getUser()) + ->withPassword($dsn->getPassword()) + ->withOptions([ + PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed + PDO::ATTR_TIMEOUT => 3, // Seconds + PDO::ATTR_PERSISTENT => true, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => true, + PDO::ATTR_STRINGIFY_FETCHES => true + ]); $pool = new PDOPool($pdoConfig, $name, 64); From a229eac2ccf652e508b81f87023de1fd65102570 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 8 Oct 2022 08:51:58 +0300 Subject: [PATCH 03/36] Renamed DatabasePool to Pools --- app/controllers/api/projects.php | 2 +- app/init.php | 4 ++-- app/realtime.php | 14 +++++++------- app/tasks/doctor.php | 2 +- app/tasks/maintenance.php | 6 +++--- app/tasks/usage.php | 6 +++--- src/Appwrite/Resque/Worker.php | 12 ++++++------ 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 22ee9e3c03..0f3d54f8ce 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -131,7 +131,7 @@ App::post('/v1/projects') 'database' => $pdo->getName() ])); - $dbForProject = DatabasePool::getDatabase($pdo->getConnection(), $cache, "_{$project->getInternalId()}"); + $dbForProject = Pools::getDatabase($pdo->getConnection(), $cache, "_{$project->getInternalId()}"); $dbForProject->create(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); $audit = new Audit($dbForProject); diff --git a/app/init.php b/app/init.php index 9feae34e63..0f6b7a7542 100644 --- a/app/init.php +++ b/app/init.php @@ -908,14 +908,14 @@ App::setResource('dbForProject', function ($dbPool, $cache, Document $project) { $database = $dbPool->getConsoleDB(); } $pdo = $dbPool->getPDOFromPool($database); - $database = DatabasePool::getDatabase($pdo->getConnection(), $cache, "_{$project->getInternalId()}"); + $database = Pools::getDatabase($pdo->getConnection(), $cache, "_{$project->getInternalId()}"); return $database; }, ['dbPool', 'cache', 'project']); App::setResource('dbForConsole', function ($dbPool, $cache) { $database = $dbPool->getConsoleDB(); $pdo = $dbPool->getPDOFromPool($database); - $database = DatabasePool::getDatabase($pdo->getConnection(), $cache, '_console'); + $database = Pools::getDatabase($pdo->getConnection(), $cache, '_console'); return $database; }, ['dbPool', 'cache']); diff --git a/app/realtime.php b/app/realtime.php index ab39a18a57..9df6ed5e4f 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -1,7 +1,7 @@ getConsoleDB(); $pdo = $dbPool->getPDOFromPool($database); - $database = DatabasePool::wait( - DatabasePool::getDatabase($pdo->getConnection(), $redis, '_console'), + $database = Pools::wait( + Pools::getDatabase($pdo->getConnection(), $redis, '_console'), 'realtime' ); @@ -109,8 +109,8 @@ function getDatabase(Registry &$register, string $projectId) $project = Authorization::skip(fn() => $database->getDocument('projects', $projectId)); $database = $project->getAttribute('database', ''); $pdo = $dbPool->getPDOFromPool($database); - $database = DatabasePool::wait( - DatabasePool::getDatabase($pdo->getConnection(), $redis, "_{$project->getInternalId()}"), + $database = Pools::wait( + Pools::getDatabase($pdo->getConnection(), $redis, "_{$project->getInternalId()}"), 'realtime' ); } @@ -479,13 +479,13 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re /** Get the console DB */ $database = $dbPool->getConsoleDB(); $pdo = $dbPool->getPDOFromPool($database); - $database = DatabasePool::getDatabase($pdo->getConnection(), $redis, '_console'); + $database = Pools::getDatabase($pdo->getConnection(), $redis, '_console'); if ($projectId !== 'console') { $project = Authorization::skip(fn() => $database->getDocument('projects', $projectId)); $database = $project->getAttribute('database', ''); $pdo = $dbPool->getPDOFromPool($database); - $database = DatabasePool::getDatabase($pdo->getConnection(), $redis, "_{$project->getInternalId()}"); + $database = Pools::getDatabase($pdo->getConnection(), $redis, "_{$project->getInternalId()}"); } /* diff --git a/app/tasks/doctor.php b/app/tasks/doctor.php index 634381ba41..6875b65092 100644 --- a/app/tasks/doctor.php +++ b/app/tasks/doctor.php @@ -96,7 +96,7 @@ $cli } try { - $dbPool = $register->get('dbPool'); /* @var $dbPool DatabasePool */ + $dbPool = $register->get('dbPool'); /* @var $dbPool Pools */ $database = $dbPool->getConsoleDB(); $pdo = $dbPool->getPDO($database); Console::success('Database............connected 👍'); diff --git a/app/tasks/maintenance.php b/app/tasks/maintenance.php index af4719d119..8d684d8bed 100644 --- a/app/tasks/maintenance.php +++ b/app/tasks/maintenance.php @@ -3,7 +3,7 @@ global $cli; use Appwrite\Auth\Auth; -use Appwrite\Database\DatabasePool; +use Appwrite\Database\Pools; use Appwrite\Event\Certificate; use Appwrite\Event\Delete; use Utopia\App; @@ -121,8 +121,8 @@ $cli $database = $dbPool->getConsoleDB(); $pdo = $dbPool->getPDO($database); - $database = DatabasePool::wait( - DatabasePool::getDatabase($pdo, $redis, '_console'), + $database = Pools::wait( + Pools::getDatabase($pdo, $redis, '_console'), 'certificates', ); diff --git a/app/tasks/usage.php b/app/tasks/usage.php index 214fd27b5d..d9215833c7 100644 --- a/app/tasks/usage.php +++ b/app/tasks/usage.php @@ -2,7 +2,7 @@ global $cli, $register; -use Appwrite\Database\DatabasePool; +use Appwrite\Database\Pools; use Appwrite\Usage\Calculators\Aggregator; use Appwrite\Usage\Calculators\Database; use Appwrite\Usage\Calculators\TimeSeries; @@ -131,8 +131,8 @@ $cli $database = $dbPool->getConsoleDB(); $pdo = $dbPool->getPDO($database); - $database = DatabasePool::wait( - DatabasePool::getDatabase($pdo, $redis, '_console'), + $database = Pools::wait( + Pools::getDatabase($pdo, $redis, '_console'), 'projects', ); diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index c1ef264670..e394f416f3 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -2,7 +2,8 @@ namespace Appwrite\Resque; -use Appwrite\Database\DatabasePool; +use Exception; +use Appwrite\Database\Pools; use Utopia\App; use Utopia\Database\Database; use Utopia\Storage\Device; @@ -13,7 +14,6 @@ use Utopia\Storage\Device\Linode; use Utopia\Storage\Device\Wasabi; use Utopia\Storage\Device\Backblaze; use Utopia\Storage\Device\S3; -use Exception; use Utopia\Database\Document; use Utopia\Database\Validator\Authorization; @@ -175,8 +175,8 @@ abstract class Worker $dbPool = $register->get('dbPool'); $namespace = "_$internalId"; $pdo = $dbPool->getPDO($database); - $dbForProject = DatabasePool::wait( - DatabasePool::getDatabase($pdo, $cache, $namespace), + $dbForProject = Pools::wait( + Pools::getDatabase($pdo, $cache, $namespace), 'projects' ); @@ -199,8 +199,8 @@ abstract class Worker $namespace = "_console"; $pdo = $dbPool->getPDO($database); - $dbForConsole = DatabasePool::wait( - DatabasePool::getDatabase($pdo, $cache, $namespace), + $dbForConsole = Pools::wait( + Pools::getDatabase($pdo, $cache, $namespace), '_metadata' ); From 690c275ee2f6aeba1508502aae813058cd12b5d9 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 8 Oct 2022 10:26:51 +0300 Subject: [PATCH 04/36] Hide `_APP_DB_PROJECT` and `_APP_DB_CONSOLE` from docs --- app/config/variables.php | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/app/config/variables.php b/app/config/variables.php index 6bcf4097ed..837cc7fccf 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -306,24 +306,24 @@ return [ 'question' => '', 'filter' => 'password' ], - [ - 'name' => '_APP_DB_PROJECT', - 'description' => 'A list of comma-separated key value pairs representing Project DBs where key is the database name and value is the DSN connection string.', - 'introduction' => 'TBD', - 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', - 'required' => true, - 'question' => '', - 'filter' => '' - ], - [ - 'name' => '_APP_DB__APP_DB_CONSOLEROOT_PASS', - 'description' => 'A key value pair representing the Console DB where key is the database name and value is the DSN connection string.', - 'introduction' => 'TBD', - 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', - 'required' => true, - 'question' => '', - 'filter' => '' - ] + // [ + // 'name' => '_APP_DB_PROJECT', + // 'description' => 'A list of comma-separated key value pairs representing Project DBs where key is the database name and value is the DSN connection string.', + // 'introduction' => 'TBD', + // 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', + // 'required' => true, + // 'question' => '', + // 'filter' => '' + // ], + // [ + // 'name' => '_APP_DB_CONSOLE', + // 'description' => 'A key value pair representing the Console DB where key is the database name and value is the DSN connection string.', + // 'introduction' => 'TBD', + // 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', + // 'required' => true, + // 'question' => '', + // 'filter' => '' + // ] ], ], [ From fc8c40c62f5f09dec80d2fb7466cc5245ab2318e Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 10 Oct 2022 19:34:57 +0300 Subject: [PATCH 05/36] Removed unused hostnames --- app/init.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/init.php b/app/init.php index 0f6b7a7542..a4bf247550 100644 --- a/app/init.php +++ b/app/init.php @@ -54,13 +54,10 @@ use Appwrite\Database\Pools; use Appwrite\Event\Delete; use Utopia\Database\Validator\Structure; use Utopia\Database\Validator\Authorization; -use Utopia\Cache\Cache; -use Utopia\Cache\Adapter\Redis as RedisCache; use Utopia\Validator\Range; use Utopia\Validator\WhiteList; use Swoole\Database\RedisConfig; use Swoole\Database\RedisPool; -use Utopia\Database\Adapter\MariaDB; use Utopia\Database\Query; use Utopia\Database\Validator\DatetimeValidator; use Utopia\Storage\Device; From f49f1b4755706b20bd80be5153dd580df58f1f93 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 15 Oct 2022 11:51:57 +0300 Subject: [PATCH 06/36] Added pools library --- composer.json | 1 + composer.lock | 91 ++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 73 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index 973aec8539..25c5750e3e 100644 --- a/composer.json +++ b/composer.json @@ -61,6 +61,7 @@ "utopia-php/websocket": "0.1.0", "utopia-php/image": "0.5.*", "utopia-php/orchestration": "0.6.*", + "utopia-php/pools": "0.1.*", "resque/php-resque": "1.3.6", "matomo/device-detector": "6.0.0", "dragonmantank/cron-expression": "3.3.1", diff --git a/composer.lock b/composer.lock index 39f94fc1a1..71bf85b379 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "568151395a8877f87d9bdce048adc2dc", + "content-hash": "0284feec79d1f1ffc39f62ac812f3da1", "packages": [ { "name": "adhocore/jwt", @@ -2060,16 +2060,16 @@ }, { "name": "utopia-php/database", - "version": "0.25.4", + "version": "0.25.5", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "2883de82eee99e5744bf6e4123095a530c48a194" + "reference": "6d1c1d46d66553154975a3e8e72d30b5bd2413d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/2883de82eee99e5744bf6e4123095a530c48a194", - "reference": "2883de82eee99e5744bf6e4123095a530c48a194", + "url": "https://api.github.com/repos/utopia-php/database/zipball/6d1c1d46d66553154975a3e8e72d30b5bd2413d9", + "reference": "6d1c1d46d66553154975a3e8e72d30b5bd2413d9", "shasum": "" }, "require": { @@ -2118,9 +2118,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.25.4" + "source": "https://github.com/utopia-php/database/tree/0.25.5" }, - "time": "2022-09-14T06:22:33+00:00" + "time": "2022-09-30T15:01:32+00:00" }, { "name": "utopia-php/domains", @@ -2449,6 +2449,59 @@ }, "time": "2022-07-13T16:47:18+00:00" }, + { + "name": "utopia-php/pools", + "version": "0.1.0", + "source": { + "type": "git", + "url": "https://github.com/utopia-php/pools.git", + "reference": "5a467a569a80aefc846a97dc195b4adc2fd71805" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/utopia-php/pools/zipball/5a467a569a80aefc846a97dc195b4adc2fd71805", + "reference": "5a467a569a80aefc846a97dc195b4adc2fd71805", + "shasum": "" + }, + "require": { + "ext-mongodb": "*", + "ext-pdo": "*", + "ext-redis": "*", + "php": ">=8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.4", + "vimeo/psalm": "4.0.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Utopia\\Pools\\": "src/Pools" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Team Appwrite", + "email": "team@appwrite.io" + } + ], + "description": "A simple library to manage connection pools", + "keywords": [ + "framework", + "php", + "pools", + "utopia" + ], + "support": { + "issues": "https://github.com/utopia-php/pools/issues", + "source": "https://github.com/utopia-php/pools/tree/0.1.0" + }, + "time": "2022-10-11T19:31:07+00:00" + }, { "name": "utopia-php/preloader", "version": "0.2.4", @@ -3536,16 +3589,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.16", + "version": "9.2.17", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "2593003befdcc10db5e213f9f28814f5aa8ac073" + "reference": "aa94dc41e8661fe90c7316849907cba3007b10d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2593003befdcc10db5e213f9f28814f5aa8ac073", - "reference": "2593003befdcc10db5e213f9f28814f5aa8ac073", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa94dc41e8661fe90c7316849907cba3007b10d8", + "reference": "aa94dc41e8661fe90c7316849907cba3007b10d8", "shasum": "" }, "require": { @@ -3601,7 +3654,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.16" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.17" }, "funding": [ { @@ -3609,7 +3662,7 @@ "type": "github" } ], - "time": "2022-08-20T05:26:47+00:00" + "time": "2022-08-30T12:24:04+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5283,16 +5336,16 @@ }, { "name": "twig/twig", - "version": "v3.4.2", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077" + "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077", - "reference": "e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58", + "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58", "shasum": "" }, "require": { @@ -5343,7 +5396,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.4.2" + "source": "https://github.com/twigphp/Twig/tree/v3.4.3" }, "funding": [ { @@ -5355,7 +5408,7 @@ "type": "tidelift" } ], - "time": "2022-08-12T06:47:24+00:00" + "time": "2022-09-28T08:42:51+00:00" } ], "aliases": [], From daecc1aa76cc80e61906845d57bcc2c5c435f895 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 15 Oct 2022 11:52:50 +0300 Subject: [PATCH 07/36] Init new connection pool, removed old extensions --- app/config/variables.php | 4 +- app/init.php | 257 +++++++++++++++++++-------- src/Appwrite/Database/Pools.php | 4 +- src/Appwrite/Extend/PDO.php | 110 ------------ src/Appwrite/Extend/PDOStatement.php | 115 ------------ 5 files changed, 184 insertions(+), 306 deletions(-) delete mode 100644 src/Appwrite/Extend/PDO.php delete mode 100644 src/Appwrite/Extend/PDOStatement.php diff --git a/app/config/variables.php b/app/config/variables.php index 837cc7fccf..f529831192 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -307,7 +307,7 @@ return [ 'filter' => 'password' ], // [ - // 'name' => '_APP_DB_PROJECT', + // 'name' => '_APP_CONNECTIONS_DB_PROJECT', // 'description' => 'A list of comma-separated key value pairs representing Project DBs where key is the database name and value is the DSN connection string.', // 'introduction' => 'TBD', // 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', @@ -316,7 +316,7 @@ return [ // 'filter' => '' // ], // [ - // 'name' => '_APP_DB_CONSOLE', + // 'name' => '_APP_CONNECTIONS_DB_CONSOLE', // 'description' => 'A key value pair representing the Console DB where key is the database name and value is the DSN connection string.', // 'introduction' => 'TBD', // 'default' => 'db_fra1_01=mysql://user:password@mariadb:3306/appwrite', diff --git a/app/init.php b/app/init.php index a4bf247550..0012fbf043 100644 --- a/app/init.php +++ b/app/init.php @@ -34,6 +34,7 @@ use Appwrite\Event\Database as EventDatabase; use Appwrite\Event\Event; use Appwrite\Event\Mail; use Appwrite\Event\Phone; +use Appwrite\Event\Delete; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\IP; use Appwrite\Network\Validator\URL; @@ -41,25 +42,19 @@ use Appwrite\OpenSSL\OpenSSL; use Appwrite\Usage\Stats; use Appwrite\Utopia\View; use Utopia\App; +use Utopia\Validator\Range; +use Utopia\Validator\WhiteList; use Utopia\Database\ID; +use Utopia\Database\Document; +use Utopia\Database\Database; +use Utopia\Database\Query; +use Utopia\Database\Validator\Authorization; +use Utopia\Database\Validator\DatetimeValidator; +use Utopia\Database\Validator\Structure; use Utopia\Logger\Logger; use Utopia\Config\Config; use Utopia\Locale\Locale; use Utopia\Registry\Registry; -use MaxMind\Db\Reader; -use PHPMailer\PHPMailer\PHPMailer; -use Utopia\Database\Document; -use Utopia\Database\Database; -use Appwrite\Database\Pools; -use Appwrite\Event\Delete; -use Utopia\Database\Validator\Structure; -use Utopia\Database\Validator\Authorization; -use Utopia\Validator\Range; -use Utopia\Validator\WhiteList; -use Swoole\Database\RedisConfig; -use Swoole\Database\RedisPool; -use Utopia\Database\Query; -use Utopia\Database\Validator\DatetimeValidator; use Utopia\Storage\Device; use Utopia\Storage\Storage; use Utopia\Storage\Device\Backblaze; @@ -68,6 +63,16 @@ use Utopia\Storage\Device\Local; use Utopia\Storage\Device\S3; use Utopia\Storage\Device\Linode; use Utopia\Storage\Device\Wasabi; +use MaxMind\Db\Reader; +use PHPMailer\PHPMailer\PHPMailer; +use Swoole\Database\PDOProxy; +use Utopia\Cache\Adapter\Redis as RedisCache; +use Utopia\Cache\Cache; +use Utopia\Database\Adapter\MariaDB; +use Utopia\Database\Adapter\MySQL; +use Utopia\Pools\Connection; +use Utopia\Pools\Group; +use Utopia\Pools\Pool; const APP_NAME = 'Appwrite'; const APP_DOMAIN = 'appwrite.io'; @@ -492,53 +497,146 @@ $register->set('logger', function () { return new Logger($adapter); }); +$register->set('pools', function () { -$register->set('dbPool', function () { - /** Parse the console databases */ - $consoleDB = App::getEnv('_APP_DB_CONSOLE', ''); - $consoleDB = explode(',', $consoleDB)[0]; - $consoleDB = explode('=', $consoleDB); - $name = $consoleDB[0]; - $dsn = $consoleDB[1]; - $consoleDBs[$name] = $dsn; + $group= new Group(); - /** Parse the project databases */ - $projectDBs = []; - $projectDB = App::getEnv('_APP_DB_PROJECT', ''); - $projectDB = explode(',', $projectDB); - foreach ($projectDB as $db) { - $db = explode('=', $db); - $name = $db[0]; - $dsn = $db[1]; - $projectDBs[$name] = $dsn; + $connections = [ + 'console' => [ + 'type' => 'database', + 'dsns' => App::getEnv('_APP_CONNECTIONS_DB_CONSOLE', ''), + 'multiple' => false, + 'schemes' => ['mariadb', 'mysql'], + ], + 'database' => [ + 'type' => 'database', + 'dsns' => App::getEnv('_APP_CONNECTIONS_DB_PROJECT', ''), + 'multiple' => true, + 'schemes' => ['mariadb', 'mysql'], + ], + 'queue' => [ + 'type' => 'queue', + 'dsns' => App::getEnv('_APP_CONNECTIONS_QUEUE', ''), + 'multiple' => false, + 'schemes' => ['redis'], + ], + 'pubsub' => [ + 'type' => 'pubsub', + 'dsns' => App::getEnv('_APP_CONNECTIONS_PUBSUB', ''), + 'multiple' => false, + 'schemes' => ['redis'], + ], + 'cache' => [ + 'type' => 'cache', + 'dsns' => App::getEnv('_APP_CONNECTIONS_CACHE', ''), + 'multiple' => true, + 'schemes' => ['redis'], + ], + ]; + + foreach ($connections as $key => $connection) { + $type = $connection['type'] ?? ''; + $dsns = $connection['dsns'] ?? ''; + $multipe = $connection['multiple'] ?? false; + $schemes = $connection['schemes'] ?? []; + + $variable = explode(',', $connection['dsns'] ?? ''); + $dsns = []; + + foreach ($variable as $dsn) { + $dsn = explode('=', $dsn); + $name = ($multipe) ? $key.'_'.$dsn[0] : $key; + $dsn = $dsn[1]; + + $dsn = new DSN($dsn); + $dsnHost = $dsn->getHost(); + $dsnPort = $dsn->getPort(); + $dsnUser = $dsn->getUser(); + $dsnPass = $dsn->getPassword(); + $dsnScheme = $dsn->getDatabase(); + + if(!in_array($dsns[$name]->getScheme(), $schemes)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid console database scheme"); + } + + /** + * Get Resource + * + * Creation could be reused accross connection types like database, cache, queue, etc. + * + * Resource assignment to an adapter will happen below. + */ + + switch ($dsn->getScheme()) { + case 'mysql': + case 'mariadb': + $resource = new PDOProxy("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnScheme};charset=utf8mb4", $dsnUser, $dsnPass, array( + PDO::ATTR_TIMEOUT => 3, // Seconds + PDO::ATTR_PERSISTENT => true, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed + PDO::ATTR_EMULATE_PREPARES => true, + PDO::ATTR_STRINGIFY_FETCHES => true + )); + break; + case 'redis': + $resource = new Redis(); + $resource->pconnect($dsnHost, $dsnHost); + if($dsnPass) { + $resource->auth($dsnPass); + } + $resource->setOption(Redis::OPT_READ_TIMEOUT, -1); + break; + + default: + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid scheme"); + break; + } + + // Get Adapter + + switch ($type) { + case 'database': + $adapter = match ($dsn->getScheme()) { + 'mariadb' => new MariaDB($resource), + 'mariadb' => new MySQL($resource), + default => null + }; + + break; + case 'queue': + //$adapter = new Queue($resource); + break; + case 'pubsub': + //$adapter = new PubSub($resource); + break; + case 'cache': + $adapter = match ($dsn->getScheme()) { + 'redis' => new RedisCache($resource), + default => null + }; + break; + + default: + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation."); + break; + } + + if(is_null($adapter)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation."); + } + + $pool = new Pool($name, 64, function () use ($adapter) { + return new Connection($adapter); + }); + + $group->add($pool); + } } - $pool = new Pools($consoleDBs, $projectDBs); - return $pool; + return $group; }); -$register->set('redisPool', function () { - $redisHost = App::getEnv('_APP_REDIS_HOST', ''); - $redisPort = App::getEnv('_APP_REDIS_PORT', ''); - $redisUser = App::getEnv('_APP_REDIS_USER', ''); - $redisPass = App::getEnv('_APP_REDIS_PASS', ''); - $redisAuth = ''; - - if ($redisUser && $redisPass) { - $redisAuth = $redisUser . ':' . $redisPass; - } - - $pool = new RedisPool( - (new RedisConfig()) - ->withHost($redisHost) - ->withPort($redisPort) - ->withAuth($redisAuth) - ->withDbIndex(0), - 64 - ); - - return $pool; -}); $register->set('influxdb', function () { // Register DB connection $host = App::getEnv('_APP_INFLUXDB_HOST', ''); @@ -594,14 +692,6 @@ $register->set('smtp', function () { $register->set('geodb', function () { return new Reader(__DIR__ . '/db/DBIP/dbip-country-lite-2022-06.mmdb'); }); -$register->set('cache', function () { - // This is usually for our workers or CLI commands scope - $redis = new Redis(); - $redis->pconnect(App::getEnv('_APP_REDIS_HOST', ''), App::getEnv('_APP_REDIS_PORT', '')); - $redis->setOption(Redis::OPT_READ_TIMEOUT, -1); - - return $redis; -}); /* * Localization @@ -899,22 +989,35 @@ App::setResource('console', function () { ]); }, []); -App::setResource('dbForProject', function ($dbPool, $cache, Document $project) { - $database = $project->getAttribute('database', ''); - if (empty($database)) { - $database = $dbPool->getConsoleDB(); - } - $pdo = $dbPool->getPDOFromPool($database); - $database = Pools::getDatabase($pdo->getConnection(), $cache, "_{$project->getInternalId()}"); - return $database; -}, ['dbPool', 'cache', 'project']); +App::setResource('dbForProject', function (Group $pools, Cache $cache, Document $project) { + $dbAdapter = $pools + ->get($project->getAttribute('database', 'console')) + ->pop() + ->getResource() + ; + + $database = new Database($dbAdapter, $cache); + + $database->setNamespace("_{$project->getInternalId()}"); + $database->setDefaultDatabase('appwrite'); -App::setResource('dbForConsole', function ($dbPool, $cache) { - $database = $dbPool->getConsoleDB(); - $pdo = $dbPool->getPDOFromPool($database); - $database = Pools::getDatabase($pdo->getConnection(), $cache, '_console'); return $database; -}, ['dbPool', 'cache']); +}, ['pools', 'cache', 'project']); + +App::setResource('dbForConsole', function (Group $pools, Cache $cache) { + $dbAdapter = $pools + ->get('console') + ->pop() + ->getResource() + ; + + $database = new Database($dbAdapter, $cache); + + $database->setNamespace('console'); + $database->setDefaultDatabase('appwrite'); + + return $database; +}, ['pools', 'cache']); App::setResource('deviceLocal', function () { return new Local(); diff --git a/src/Appwrite/Database/Pools.php b/src/Appwrite/Database/Pools.php index facdaf3853..929e3043ba 100644 --- a/src/Appwrite/Database/Pools.php +++ b/src/Appwrite/Database/Pools.php @@ -122,7 +122,7 @@ class Pools */ public function getPDOFromPool(string $name): PDOWrapper { - $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_CONNECTIONS_DB_PROJECT in .env", 500); $pdo = $pool->get(); return $pdo; } @@ -135,7 +135,7 @@ class Pools public function getAnyFromPool(): PDOWrapper { $name = array_rand($this->pools); - $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_CONNECTIONS_DB_PROJECT in .env", 500); $pdo = $pool->get(); return $pdo; } diff --git a/src/Appwrite/Extend/PDO.php b/src/Appwrite/Extend/PDO.php deleted file mode 100644 index bc3f42afb9..0000000000 --- a/src/Appwrite/Extend/PDO.php +++ /dev/null @@ -1,110 +0,0 @@ -dsn = $dsn; - $this->username = $username; - $this->passwd = $passwd; - $this->options = $options; - - $this->pdo = new PDONative($dsn, $username, $passwd, $options); - } - - public function setAttribute($attribute, $value) - { - return $this->pdo->setAttribute($attribute, $value); - } - - public function prepare($statement, $driver_options = null) - { - return new PDOStatement($this, $this->pdo->prepare($statement, [])); - } - - public function quote($string, $parameter_type = PDONative::PARAM_STR) - { - return $this->pdo->quote($string, $parameter_type); - } - - public function beginTransaction() - { - try { - $result = $this->pdo->beginTransaction(); - } catch (\Throwable $th) { - $this->pdo = $this->reconnect(); - $result = $this->pdo->beginTransaction(); - } - - return $result; - } - - public function rollBack() - { - try { - $result = $this->pdo->rollBack(); - } catch (\Throwable $th) { - $this->pdo = $this->reconnect(); - return false; - } - - return $result; - } - - public function commit() - { - try { - $result = $this->pdo->commit(); - } catch (\Throwable $th) { - $this->pdo = $this->reconnect(); - $result = $this->pdo->commit(); - } - - return $result; - } - - public function reconnect(): PDONative - { - $this->pdo = new PDONative($this->dsn, $this->username, $this->passwd, $this->options); - - echo '[PDO] MySQL connection restarted' . PHP_EOL; - - // Connection settings - $this->pdo->setAttribute(PDONative::ATTR_DEFAULT_FETCH_MODE, PDONative::FETCH_ASSOC); // Return arrays - $this->pdo->setAttribute(PDONative::ATTR_ERRMODE, PDONative::ERRMODE_EXCEPTION); // Handle all errors with exceptions - - return $this->pdo; - } -} diff --git a/src/Appwrite/Extend/PDOStatement.php b/src/Appwrite/Extend/PDOStatement.php deleted file mode 100644 index 9c5a83ec34..0000000000 --- a/src/Appwrite/Extend/PDOStatement.php +++ /dev/null @@ -1,115 +0,0 @@ -pdo = &$pdo; - $this->PDOStatement = $PDOStatement; - } - - public function bindValue($parameter, $value, $data_type = PDONative::PARAM_STR) - { - $this->values[$parameter] = ['value' => $value, 'data_type' => $data_type]; - - $result = $this->PDOStatement->bindValue($parameter, $value, $data_type); - - return $result; - } - - public function bindParam($parameter, &$variable, $data_type = PDONative::PARAM_STR, $length = null, $driver_options = null) - { - $this->params[$parameter] = ['value' => &$variable, 'data_type' => $data_type, 'length' => $length, 'driver_options' => $driver_options]; - - $result = $this->PDOStatement->bindParam($parameter, $variable, $data_type, $length, $driver_options); - - return $result; - } - - public function bindColumn($column, &$param, $type = null, $maxlen = null, $driverdata = null) - { - $this->columns[$column] = ['param' => &$param, 'type' => $type, 'maxlen' => $maxlen, 'driverdata' => $driverdata]; - - $result = $this->PDOStatement->bindColumn($column, $param, $type, $maxlen, $driverdata); - - return $result; - } - - public function execute($input_parameters = null) - { - try { - $result = $this->PDOStatement->execute($input_parameters); - } catch (\Throwable $th) { - $this->pdo = $this->pdo->reconnect(); - $this->PDOStatement = $this->pdo->prepare($this->PDOStatement->queryString, []); - - foreach ($this->values as $key => $set) { - $this->PDOStatement->bindValue($key, $set['value'], $set['data_type']); - } - - foreach ($this->params as $key => $set) { - $this->PDOStatement->bindParam($key, $set['variable'], $set['data_type'], $set['length'], $set['driver_options']); - } - - foreach ($this->columns as $key => $set) { - $this->PDOStatement->bindColumn($key, $set['param'], $set['type'], $set['maxlen'], $set['driverdata']); - } - - $result = $this->PDOStatement->execute($input_parameters); - } - - return $result; - } - - public function fetch($fetch_style = PDONative::FETCH_ASSOC, $cursor_orientation = PDONative::FETCH_ORI_NEXT, $cursor_offset = 0) - { - $result = $this->PDOStatement->fetch($fetch_style, $cursor_orientation, $cursor_offset); - - return $result; - } - - /** - * Fetch All - * - * @param int $fetch_style - * @param mixed $fetch_args - * - * @return array|false - */ - public function fetchAll(int $fetch_style = PDO::FETCH_BOTH, mixed ...$fetch_args) - { - $result = $this->PDOStatement->fetchAll(); - - return $result; - } -} From daa0ab51a6f73b1997d850ede28c40fee329f937 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 15 Oct 2022 15:32:59 +0300 Subject: [PATCH 08/36] Cast port to integer --- src/Appwrite/DSN/DSN.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Appwrite/DSN/DSN.php b/src/Appwrite/DSN/DSN.php index 5605640989..11a25d5b18 100644 --- a/src/Appwrite/DSN/DSN.php +++ b/src/Appwrite/DSN/DSN.php @@ -25,9 +25,9 @@ class DSN protected string $host; /** - * @var ?string + * @var ?int */ - protected ?string $port; + protected ?int $port; /** * @var ?string @@ -58,7 +58,7 @@ class DSN $this->user = $parts['user'] ?? null; $this->password = $parts['pass'] ?? null; $this->host = $parts['host'] ?? null; - $this->port = $parts['port'] ?? null; + $this->port = (int)$parts['port'] ?? null; $this->database = $parts['path'] ?? null; $this->query = $parts['query'] ?? null; } @@ -106,9 +106,9 @@ class DSN /** * Return the port * - * @return ?string + * @return ?int */ - public function getPort(): ?string + public function getPort(): ?int { return $this->port; } From 0e9c6db759ddd738e19a316ff85379b6d071ca25 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 15 Oct 2022 16:49:37 +0300 Subject: [PATCH 09/36] Added new connections --- .env | 7 +++-- app/views/install/compose.phtml | 40 ++++++++++++------------- docker-compose.yml | 53 ++++++++++++++++----------------- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/.env b/.env index 840e66398b..b0887c23ea 100644 --- a/.env +++ b/.env @@ -23,8 +23,11 @@ _APP_DB_SCHEMA=appwrite _APP_DB_USER=user _APP_DB_PASS=password _APP_DB_ROOT_PASS=rootsecretpassword -_APP_DB_PROJECT=db_fra1_02=mysql://user:password@mariadb:3306/appwrite -_APP_DB_CONSOLE=db_fra1_01=mysql://user:password@mariadb:3306/appwrite +_APP_CONNECTIONS_DB_PROJECT=db_fra1_02=mysql://user:password@mariadb:3306/appwrite +_APP_CONNECTIONS_DB_CONSOLE=db_fra1_01=mysql://user:password@mariadb:3306/appwrite +_APP_CONNECTIONS_CACHE=redis_fra1_01=redis://redis:6379 +_APP_CONNECTIONS_QUEUE=redis_fra1_01=redis://redis:6379 +_APP_CONNECTIONS_PUBSUB=redis_fra1_01=redis://redis:6379 _APP_STORAGE_DEVICE=Local _APP_STORAGE_S3_ACCESS_KEY= _APP_STORAGE_S3_SECRET= diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index 944d3eab0a..c10a027500 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -92,8 +92,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE @@ -183,8 +183,8 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_REDIS_HOST - _APP_REDIS_PORT - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_USAGE_STATS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -207,8 +207,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -258,8 +258,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_STORAGE_DEVICE - _APP_STORAGE_S3_ACCESS_KEY - _APP_STORAGE_S3_SECRET @@ -304,8 +304,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -329,8 +329,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -358,8 +358,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -382,8 +382,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_FUNCTIONS_TIMEOUT - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST @@ -515,8 +515,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE @@ -539,8 +539,8 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_INFLUXDB_HOST - _APP_INFLUXDB_PORT - _APP_USAGE_TIMESERIES_INTERVAL diff --git a/docker-compose.yml b/docker-compose.yml index a207d85c91..94446d5359 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -136,8 +136,11 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_PROJECT - - _APP_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE + - _APP_CONNECTIONS_PUBSUB - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE @@ -180,7 +183,6 @@ services: container_name: appwrite-realtime build: context: . - restart: unless-stopped ports: - 9505:80 labels: @@ -213,8 +215,8 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_REDIS_HOST - _APP_REDIS_PORT - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_USAGE_STATS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -240,8 +242,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -297,8 +299,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - *x-env-storage - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -327,8 +329,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -355,8 +357,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -386,8 +388,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -413,8 +415,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_FUNCTIONS_TIMEOUT - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST @@ -547,8 +549,8 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE @@ -577,8 +579,8 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_INFLUXDB_HOST - _APP_INFLUXDB_PORT - _APP_USAGE_TIMESERIES_INTERVAL @@ -612,8 +614,8 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 - - _APP_DB_CONSOLE - - _APP_DB_PROJECT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT - _APP_INFLUXDB_HOST - _APP_INFLUXDB_PORT - _APP_USAGE_TIMESERIES_INTERVAL @@ -666,7 +668,6 @@ services: # smtp: # image: appwrite/smtp:1.2.0 # container_name: appwrite-smtp - # restart: unless-stopped # networks: # - appwrite # environment: @@ -753,7 +754,6 @@ services: image: adminer container_name: appwrite-adminer <<: *x-logging - restart: always ports: - 9506:8080 networks: @@ -761,7 +761,6 @@ services: # redis-commander: # image: rediscommander/redis-commander:latest - # restart: unless-stopped # networks: # - appwrite # environment: @@ -771,7 +770,6 @@ services: # resque: # image: appwrite/resque-web:1.1.0 - # restart: unless-stopped # networks: # - appwrite # ports: @@ -785,7 +783,6 @@ services: # chronograf: # image: chronograf:1.6 # container_name: appwrite-chronograf - # restart: unless-stopped # networks: # - appwrite # volumes: From 0506dbb30e09ab2c5ac2215a8e5b6eaadc7db6a0 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 15 Oct 2022 17:14:17 +0300 Subject: [PATCH 10/36] Adapted HTTP API --- app/controllers/api/projects.php | 21 ++++----- app/http.php | 25 ++++------- app/init.php | 76 ++++++++++++++++++++++---------- 3 files changed, 73 insertions(+), 49 deletions(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 0f3d54f8ce..aca98acd6b 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -2,7 +2,6 @@ use Appwrite\Auth\Auth; use Appwrite\Auth\Validator\Password; -use Appwrite\Database\Pools; use Appwrite\Event\Certificate; use Appwrite\Event\Delete; use Appwrite\Event\Validator\Event; @@ -29,10 +28,9 @@ use Utopia\Database\Validator\UID; use Utopia\Domains\Domain; use Utopia\Registry\Registry; use Appwrite\Extend\Exception; -use Utopia\Cache\Adapter\Redis; -use Utopia\Cache\Cache; -use Utopia\Database\Adapter\MariaDB; use Appwrite\Utopia\Database\Validator\Queries\Projects; +use Utopia\Cache\Cache; +use Utopia\Pools\Group; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\Hostname; @@ -75,8 +73,8 @@ App::post('/v1/projects') ->inject('response') ->inject('dbForConsole') ->inject('cache') - ->inject('dbPool') - ->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, \Redis $cache, Pools $dbPool) { + ->inject('pools') + ->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Cache $cache, Group $pools) { $team = $dbForConsole->getDocument('teams', $teamId); if ($team->isEmpty()) { @@ -90,13 +88,13 @@ App::post('/v1/projects') } $projectId = ($projectId == 'unique()') ? ID::unique() : $projectId; + $databases = Config::getParam('pools-database', []); + $database = $databases[array_rand($databases)]; if ($projectId === 'console') { throw new Exception(Exception::PROJECT_RESERVED_PROJECT, "'console' is a reserved project."); } - $pdo = $dbPool->getAnyFromPool(); - $project = $dbForConsole->createDocument('projects', new Document([ '$id' => $projectId, '$permissions' => [ @@ -128,10 +126,13 @@ App::post('/v1/projects') 'domains' => null, 'auths' => $auths, 'search' => implode(' ', [$projectId, $name]), - 'database' => $pdo->getName() + 'database' => $database, ])); - $dbForProject = Pools::getDatabase($pdo->getConnection(), $cache, "_{$project->getInternalId()}"); + $dbForProject = new Database($pools->get($database)->pop()->getResource(), $cache); + $dbForProject->setNamespace("_{$project->getInternalId()}"); + $dbForProject->setDefaultDatabase('appwrite'); + $dbForProject->create(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); $audit = new Audit($dbForProject); diff --git a/app/http.php b/app/http.php index 93a977490f..e0ae19648c 100644 --- a/app/http.php +++ b/app/http.php @@ -22,6 +22,7 @@ use Utopia\Swoole\Files; use Appwrite\Utopia\Request; use Utopia\Logger\Log; use Utopia\Logger\Log\User; +use Utopia\Pools\Group; $http = new Server("0.0.0.0", App::getEnv('PORT', 80)); @@ -60,11 +61,8 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { go(function () use ($register, $app) { - $redis = $register->get('redisPool')->get(); - App::setResource('cache', fn() => $redis); - - $dbPool = $register->get('dbPool'); - App::setResource('dbPool', fn() => $dbPool); + $pools = $register->get('pools'); /** @var Group $pools */ + App::setResource('pools', fn() => $pools); // wait for database to be ready $attempts = 0; @@ -91,7 +89,8 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { $collections = Config::getParam('collections', []); if (!$dbForConsole->exists(App::getEnv('_APP_DB_SCHEMA', 'appwrite'))) { - $redis->flushAll(); + //$redis->flushAll(); + // $pools->get('cache')->pop()->getResource()->flushAll(); Console::success('[Setup] - Creating database: appwrite...'); @@ -222,7 +221,7 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { $dbForConsole->createCollection('bucket_' . $bucket->getInternalId(), $attributes, $indexes); } - $dbPool->reset(); + $pools->reclaim(); Console::success('[Setup] - Server database init completed...'); }); @@ -255,11 +254,8 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $app = new App('UTC'); - $redis = $register->get('redisPool')->get(); - App::setResource('cache', fn() => $redis); - - $dbPool = $register->get('dbPool'); - App::setResource('dbPool', fn() => $dbPool); + $pools = $register->get('pools'); + App::setResource('pools', fn() => $pools); try { Authorization::cleanRoles(); @@ -350,10 +346,7 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo $swooleResponse->end(\json_encode($output)); } finally { - $dbPool->reset(); - /** @var RedisPool $redisPool */ - $redisPool = $register->get('redisPool'); - $redisPool->put($redis); + $pools->reclaim(); } }); diff --git a/app/init.php b/app/init.php index 0012fbf043..d4cd78515a 100644 --- a/app/init.php +++ b/app/init.php @@ -66,8 +66,10 @@ use Utopia\Storage\Device\Wasabi; use MaxMind\Db\Reader; use PHPMailer\PHPMailer\PHPMailer; use Swoole\Database\PDOProxy; +use Utopia\Cache\Adapter\None; use Utopia\Cache\Adapter\Redis as RedisCache; use Utopia\Cache\Cache; +use Utopia\CLI\Console; use Utopia\Database\Adapter\MariaDB; use Utopia\Database\Adapter\MySQL; use Utopia\Pools\Connection; @@ -529,7 +531,7 @@ $register->set('pools', function () { 'cache' => [ 'type' => 'cache', 'dsns' => App::getEnv('_APP_CONNECTIONS_CACHE', ''), - 'multiple' => true, + 'multiple' => false, // TODO add cache sharding 'schemes' => ['redis'], ], ]; @@ -539,14 +541,18 @@ $register->set('pools', function () { $dsns = $connection['dsns'] ?? ''; $multipe = $connection['multiple'] ?? false; $schemes = $connection['schemes'] ?? []; - - $variable = explode(',', $connection['dsns'] ?? ''); - $dsns = []; + $config = []; + $dsns = explode(',', $connection['dsns'] ?? ''); - foreach ($variable as $dsn) { + foreach ($dsns as &$dsn) { $dsn = explode('=', $dsn); $name = ($multipe) ? $key.'_'.$dsn[0] : $key; - $dsn = $dsn[1]; + $dsn = $dsn[1] ?? ''; + $config[] = $name; + + if(empty($dsn)) { + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Missing value for DSN connection in {$key}"); + } $dsn = new DSN($dsn); $dsnHost = $dsn->getHost(); @@ -555,7 +561,7 @@ $register->set('pools', function () { $dsnPass = $dsn->getPassword(); $dsnScheme = $dsn->getDatabase(); - if(!in_array($dsns[$name]->getScheme(), $schemes)) { + if(!in_array($dsn->getScheme(), $schemes)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid console database scheme"); } @@ -570,18 +576,20 @@ $register->set('pools', function () { switch ($dsn->getScheme()) { case 'mysql': case 'mariadb': - $resource = new PDOProxy("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnScheme};charset=utf8mb4", $dsnUser, $dsnPass, array( - PDO::ATTR_TIMEOUT => 3, // Seconds - PDO::ATTR_PERSISTENT => true, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed - PDO::ATTR_EMULATE_PREPARES => true, - PDO::ATTR_STRINGIFY_FETCHES => true - )); + $resource = new PDOProxy(function() use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnScheme) { + return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnScheme};charset=utf8mb4", $dsnUser, $dsnPass, array( + PDO::ATTR_TIMEOUT => 3, // Seconds + PDO::ATTR_PERSISTENT => true, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed + PDO::ATTR_EMULATE_PREPARES => true, + PDO::ATTR_STRINGIFY_FETCHES => true + )); + }); break; case 'redis': $resource = new Redis(); - $resource->pconnect($dsnHost, $dsnHost); + $resource->pconnect($dsnHost, $dsnPort); if($dsnPass) { $resource->auth($dsnPass); } @@ -599,7 +607,7 @@ $register->set('pools', function () { case 'database': $adapter = match ($dsn->getScheme()) { 'mariadb' => new MariaDB($resource), - 'mariadb' => new MySQL($resource), + 'mysql' => new MySQL($resource), default => null }; @@ -627,13 +635,21 @@ $register->set('pools', function () { } $pool = new Pool($name, 64, function () use ($adapter) { - return new Connection($adapter); + return $adapter; }); $group->add($pool); } + + Config::setParam('pools-'.$key, $config); } + Console::log('Filling pools...'); + + $group->fill(); + + Console::success('Pools are ready.'); + return $group; }); @@ -989,20 +1005,23 @@ App::setResource('console', function () { ]); }, []); -App::setResource('dbForProject', function (Group $pools, Cache $cache, Document $project) { +App::setResource('dbForProject', function (Group $pools, Database $dbForConsole, Cache $cache, Document $project) { + if($project->isEmpty() || $project->getId() === 'console') { + return $dbForConsole; + } + $dbAdapter = $pools - ->get($project->getAttribute('database', 'console')) + ->get($project->getAttribute('database')) ->pop() ->getResource() ; $database = new Database($dbAdapter, $cache); - - $database->setNamespace("_{$project->getInternalId()}"); + $database->setNamespace('_'.$project->getInternalId()); $database->setDefaultDatabase('appwrite'); return $database; -}, ['pools', 'cache', 'project']); +}, ['pools', 'dbForConsole', 'cache', 'project']); App::setResource('dbForConsole', function (Group $pools, Cache $cache) { $dbAdapter = $pools @@ -1019,6 +1038,17 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) { return $database; }, ['pools', 'cache']); +App::setResource('cache', function (Group $pools) { + $cacheAdapter = $pools + ->get('cache') + ->pop() + ->getResource() + ; + + return new Cache(new None()); + return new Cache($cacheAdapter); +}, ['pools']); + App::setResource('deviceLocal', function () { return new Local(); }); From 5f2def488ea651d83f94324d9f82d8ad4e3512ef Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 15 Oct 2022 17:21:17 +0300 Subject: [PATCH 11/36] Deprecated old pool --- src/Appwrite/Database/PDOPool.php | 47 ------ src/Appwrite/Database/PDOWrapper.php | 27 ---- src/Appwrite/Database/Pools.php | 220 --------------------------- 3 files changed, 294 deletions(-) delete mode 100644 src/Appwrite/Database/PDOPool.php delete mode 100644 src/Appwrite/Database/PDOWrapper.php delete mode 100644 src/Appwrite/Database/Pools.php diff --git a/src/Appwrite/Database/PDOPool.php b/src/Appwrite/Database/PDOPool.php deleted file mode 100644 index a3db40f754..0000000000 --- a/src/Appwrite/Database/PDOPool.php +++ /dev/null @@ -1,47 +0,0 @@ -pool = new SwoolePDOPool($pdoConfig, $size); - $this->name = $name; - } - - public function getActiveConnections() - { - return $this->activeConnections; - } - - public function get(float $timeout = -1): PDOWrapper - { - $pdo = $this->pool->get($timeout); - $this->activeConnections[] = $pdo; - return new PDOWrapper($pdo, $this->name); - } - - public function put(PDOWrapper $pdo): void - { - $this->pool->put($pdo->getConnection()); - unset($this->activeConnections[array_search($pdo, $this->activeConnections)]); - } - - public function reset(): void - { - foreach ($this->activeConnections as $connection) { - $this->pool->put($connection); - } - $this->activeConnections = []; - } -} diff --git a/src/Appwrite/Database/PDOWrapper.php b/src/Appwrite/Database/PDOWrapper.php deleted file mode 100644 index 7e2b2b7b6f..0000000000 --- a/src/Appwrite/Database/PDOWrapper.php +++ /dev/null @@ -1,27 +0,0 @@ -connection = $connection; - $this->name = $name; - } - - public function getName() - { - return $this->name; - } - - public function getConnection() - { - return $this->connection; - } -} diff --git a/src/Appwrite/Database/Pools.php b/src/Appwrite/Database/Pools.php deleted file mode 100644 index 929e3043ba..0000000000 --- a/src/Appwrite/Database/Pools.php +++ /dev/null @@ -1,220 +0,0 @@ -consoleDB = array_key_first($consoleDB); - $this->dsns = array_merge($consoleDB, $projectDB); - - /** Create PDO pool instances for all the dsns */ - foreach ($this->dsns as $name => $dsn) { - $dsn = new DSN($dsn); - $pdoConfig = (new PDOConfig()) - ->withHost($dsn->getHost()) - ->withPort($dsn->getPort()) - ->withDbName($dsn->getDatabase()) - ->withCharset('utf8mb4') - ->withUsername($dsn->getUser()) - ->withPassword($dsn->getPassword()) - ->withOptions([ - PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed - PDO::ATTR_TIMEOUT => 3, // Seconds - PDO::ATTR_PERSISTENT => true, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_EMULATE_PREPARES => true, - PDO::ATTR_STRINGIFY_FETCHES => true - ]); - - $pool = new PDOPool($pdoConfig, $name, 64); - - $this->pools[$name] = $pool; - } - } - - /** - * Get a single PDO instance by database name - * - * @param string $name - * - * @return ?PDO - */ - public function getPDO(string $name): ?PDO - { - $dsn = $this->dsns[$name] ?? throw new Exception("Database with name : $name not found.", 500); - - $dsn = new DSN($dsn); - $dbHost = $dsn->getHost(); - $dbPort = $dsn->getPort(); - $dbUser = $dsn->getUser(); - $dbPass = $dsn->getPassword(); - $dbScheme = $dsn->getDatabase(); - - $pdo = new PDO("mysql:host={$dbHost};port={$dbPort};dbname={$dbScheme};charset=utf8mb4", $dbUser, $dbPass, array( - PDO::ATTR_TIMEOUT => 3, // Seconds - PDO::ATTR_PERSISTENT => true, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed - PDO::ATTR_EMULATE_PREPARES => true, - PDO::ATTR_STRINGIFY_FETCHES => true - )); - - return $pdo; - } - - /** - * Get a PDO instance from the list of available database pools. Meant to be used in co-routines - * - * @param string $projectId - * - * @return array - */ - public function getPDOFromPool(string $name): PDOWrapper - { - $pool = $this->pools[$name] ?? throw new Exception("Database pool with name : $name not found. Check the value of _APP_CONNECTIONS_DB_PROJECT in .env", 500); - $pdo = $pool->get(); - return $pdo; - } - - /** - * Get a random PDO instance from the available database pools - * - * @return PDOWrapper - */ - public function getAnyFromPool(): PDOWrapper - { - $name = array_rand($this->pools); - $pool = $this->pools[$name] ?? throw new Exception("Database pool with name : $name not found. Check the value of _APP_CONNECTIONS_DB_PROJECT in .env", 500); - $pdo = $pool->get(); - return $pdo; - } - - public function reset(): void - { - foreach ($this->pools as $pool) { - $pool->reset(); - } - } - - /** - * Return a PDO instance back to its database pool - * - * @param PDOProxy $db - * @param string $name - * - * @return void - */ - public function put(PDOProxy $db, string $name): void - { - $pool = $this->pools[$name] ?? null; - if ($pool === null) { - throw new Exception("Failed to put PDO into database pool. Database pool with name : $name not found", 500); - } - $pool->put($db); - } - - /** - * Get the name of the console DB - * - * @return ?string - */ - public function getConsoleDB(): ?string - { - if (empty($this->consoleDB)) { - throw new Exception('Console DB is not defined', 500); - }; - - return $this->consoleDB; - } - - public static function wait(Database $database, string $collection) - { - $attempts = 0; - do { - try { - $attempts++; - if (!$database->exists($database->getDefaultDatabase(), $collection)) { - 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 $database; - } - - /** - * Get a database instance from a PDO and cache - * - * @param PDO|PDOProxy $pdo - * @param \Redis $redis - * @param string $namespace - * - * @return Database - */ - public static function getDatabase(PDO|PDOProxy $pdo, \Redis $redis, string $namespace = ''): Database - { - $cache = new Cache(new RedisCache($redis)); - $database = new Database(new MariaDB($pdo), $cache); - $database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); - $database->setNamespace($namespace); - return $database; - } -} From 95a9ded28f52a3aaa39fdc278794f6e80110e680 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 15 Oct 2022 21:17:03 +0300 Subject: [PATCH 12/36] Adjusted compose files and tests --- app/init.php | 7 ++- app/views/install/compose.phtml | 31 ++++++++++-- docker-compose.yml | 21 ++++++++ src/Appwrite/Resque/Worker.php | 87 ++++++++++++++++++++++----------- tests/unit/DSN/DSNTest.php | 4 +- 5 files changed, 110 insertions(+), 40 deletions(-) diff --git a/app/init.php b/app/init.php index d4cd78515a..c4f7f32360 100644 --- a/app/init.php +++ b/app/init.php @@ -498,7 +498,6 @@ $register->set('logger', function () { $adapter = new $classname($providerConfig); return new Logger($adapter); }); - $register->set('pools', function () { $group= new Group(); @@ -551,7 +550,8 @@ $register->set('pools', function () { $config[] = $name; if(empty($dsn)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, "Missing value for DSN connection in {$key}"); + //throw new Exception(Exception::GENERAL_SERVER_ERROR, "Missing value for DSN connection in {$key}"); + continue; } $dsn = new DSN($dsn); @@ -652,7 +652,6 @@ $register->set('pools', function () { return $group; }); - $register->set('influxdb', function () { // Register DB connection $host = App::getEnv('_APP_INFLUXDB_HOST', ''); @@ -1009,7 +1008,7 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForConsole, if($project->isEmpty() || $project->getId() === 'console') { return $dbForConsole; } - + $dbAdapter = $pools ->get($project->getAttribute('database')) ->pop() diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index c10a027500..164e370d93 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -94,6 +94,9 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE + - _APP_CONNECTIONS_PUBSUB - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE @@ -185,6 +188,8 @@ services: - _APP_REDIS_PORT - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_PUBSUB - _APP_USAGE_STATS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -209,6 +214,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -231,6 +238,7 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -260,6 +268,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_STORAGE_DEVICE - _APP_STORAGE_S3_ACCESS_KEY - _APP_STORAGE_S3_SECRET @@ -306,6 +316,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -331,6 +343,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -360,6 +374,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -384,6 +400,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_FUNCTIONS_TIMEOUT - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST @@ -468,6 +486,7 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_CONNECTIONS_QUEUE - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE @@ -491,6 +510,7 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_CONNECTIONS_QUEUE - _APP_SMS_PROVIDER - _APP_SMS_FROM - _APP_LOGGING_PROVIDER @@ -517,6 +537,7 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE @@ -541,6 +562,7 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE - _APP_INFLUXDB_HOST - _APP_INFLUXDB_PORT - _APP_USAGE_TIMESERIES_INTERVAL @@ -568,11 +590,9 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 - - _APP_DB_HOST - - _APP_DB_PORT - - _APP_DB_SCHEMA - - _APP_DB_USER - - _APP_DB_PASS + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE - _APP_INFLUXDB_HOST - _APP_INFLUXDB_PORT - _APP_USAGE_TIMESERIES_INTERVAL @@ -600,6 +620,7 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_CONNECTIONS_QUEUE mariadb: image: mariadb:10.7 # fix issues when upgrading using: mysql_upgrade -u root -p diff --git a/docker-compose.yml b/docker-compose.yml index 94446d5359..4dff4f5ffc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -217,6 +217,8 @@ services: - _APP_REDIS_PORT - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_PUBSUB - _APP_USAGE_STATS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -244,6 +246,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -270,6 +274,7 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -301,6 +306,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - *x-env-storage - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -331,6 +338,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -359,6 +368,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -390,6 +401,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -417,6 +430,8 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_CONNECTIONS_QUEUE - _APP_FUNCTIONS_TIMEOUT - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST @@ -494,6 +509,7 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_CONNECTIONS_QUEUE - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE @@ -521,6 +537,7 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_CONNECTIONS_QUEUE - _APP_SMS_PROVIDER - _APP_SMS_FROM - _APP_LOGGING_PROVIDER @@ -551,6 +568,7 @@ services: - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE @@ -581,6 +599,7 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE - _APP_INFLUXDB_HOST - _APP_INFLUXDB_PORT - _APP_USAGE_TIMESERIES_INTERVAL @@ -616,6 +635,7 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE - _APP_INFLUXDB_HOST - _APP_INFLUXDB_PORT - _APP_USAGE_TIMESERIES_INTERVAL @@ -646,6 +666,7 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_CONNECTIONS_QUEUE mariadb: image: mariadb:10.7 # fix issues when upgrading using: mysql_upgrade -u root -p diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index e394f416f3..0010f491e4 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -5,6 +5,8 @@ namespace Appwrite\Resque; use Exception; use Appwrite\Database\Pools; use Utopia\App; +use Utopia\Cache\Adapter\None; +use Utopia\Cache\Cache; use Utopia\Database\Database; use Utopia\Storage\Device; use Utopia\Storage\Storage; @@ -134,8 +136,14 @@ abstract class Worker */ public function tearDown(): void { + global $register; + try { + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + $pools->reclaim(); + $this->shutdown(); + } catch (\Throwable $error) { foreach (self::$errorCallbacks as $errorCallback) { $errorCallback($error, "shutdown", $this->getName()); @@ -165,22 +173,24 @@ abstract class Worker protected function getProjectDB(Document $project): Database { global $register; - $database = $project->getAttribute('database', ''); - $internalId = $project->getInternalId(); - if (empty($database)) { - throw new \Exception('Database name not provided - cannot get database'); + + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + + if($project->isEmpty() || $project->getId() === 'console') { + return $this->getConsoleDB(); } - - $cache = $register->get('cache'); - $dbPool = $register->get('dbPool'); - $namespace = "_$internalId"; - $pdo = $dbPool->getPDO($database); - $dbForProject = Pools::wait( - Pools::getDatabase($pdo, $cache, $namespace), - 'projects' - ); - - return $dbForProject; + + $dbAdapter = $pools + ->get($project->getAttribute('database')) + ->pop() + ->getResource() + ; + + $database = new Database($dbAdapter, $this->getCache()); + $database->setNamespace('_'.$project->getInternalId()); + $database->setDefaultDatabase('appwrite'); + + return $database; } /** @@ -190,21 +200,41 @@ abstract class Worker protected function getConsoleDB(): Database { global $register; - $cache = $register->get('cache'); - $dbPool = $register->get('dbPool'); - $database = $dbPool->getConsoleDB(); - if (empty($database)) { - throw new \Exception('Database name not provided - cannot get database'); - } - $namespace = "_console"; - $pdo = $dbPool->getPDO($database); - $dbForConsole = Pools::wait( - Pools::getDatabase($pdo, $cache, $namespace), - '_metadata' - ); + $pools = $register->get('pools'); /* @var \Utopia\Pools\Group $pools */ + + $dbAdapter = $pools + ->get('console') + ->pop() + ->getResource() + ; - return $dbForConsole; + $database = new Database($dbAdapter, $this->getCache()); + + $database->setNamespace('console'); + $database->setDefaultDatabase('appwrite'); + + return $database; + } + + /** + * Get Cache + * @return Cache + */ + protected function getCache(): Cache + { + global $register; + + $pools = $register->get('pools'); /* @var \Utopia\Pools\Group $pools */ + + $pools + ->get('cache') + ->pop() + ->getResource() + ; + + return new Cache(new None()); + // return new Cache($cacheAdapter); } /** @@ -227,7 +257,6 @@ abstract class Worker return $this->getDevice(APP_STORAGE_UPLOADS . '/app-' . $projectId); } - /** * Get Builds Storage Device * @param string $projectId of the project diff --git a/tests/unit/DSN/DSNTest.php b/tests/unit/DSN/DSNTest.php index d1f5ba1197..6565e0da19 100644 --- a/tests/unit/DSN/DSNTest.php +++ b/tests/unit/DSN/DSNTest.php @@ -14,7 +14,7 @@ class DSNTest extends TestCase $this->assertEquals("user", $dsn->getUser()); $this->assertEquals("password", $dsn->getPassword()); $this->assertEquals("localhost", $dsn->getHost()); - $this->assertEquals("3306", $dsn->getPort()); + $this->assertEquals(3306, $dsn->getPort()); $this->assertEquals("database", $dsn->getDatabase()); $this->assertEquals("charset=utf8&timezone=UTC", $dsn->getQuery()); @@ -23,7 +23,7 @@ class DSNTest extends TestCase $this->assertEquals("user", $dsn->getUser()); $this->assertNull($dsn->getPassword()); $this->assertEquals("localhost", $dsn->getHost()); - $this->assertEquals("3306", $dsn->getPort()); + $this->assertEquals(3306, $dsn->getPort()); $this->assertEquals("database", $dsn->getDatabase()); $this->assertEquals("charset=utf8&timezone=UTC", $dsn->getQuery()); From d5849c39f3ce932cf57f336e473b5b7b223a1d03 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sat, 15 Oct 2022 21:57:55 +0300 Subject: [PATCH 13/36] Removed unused namespaces --- app/controllers/api/account.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index a4a5ec776f..fe86ee1837 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -6,7 +6,6 @@ use Appwrite\SMS\Adapter\Mock; use Appwrite\Auth\Validator\Password; use Appwrite\Auth\Validator\Phone; use Appwrite\Detector\Detector; -use Appwrite\Event\Audit; use Appwrite\Event\Event; use Appwrite\Event\Mail; use Appwrite\Event\Phone as EventPhone; @@ -40,7 +39,6 @@ use Utopia\Database\Validator\UID; use Utopia\Locale\Locale; use Utopia\Validator\ArrayList; use Utopia\Validator\Assoc; -use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; From 13847fc1550312fc7746f905426a36e7bacae886 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 16 Oct 2022 01:44:03 +0300 Subject: [PATCH 14/36] Added verbose error log for dev mode --- app/cli.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/cli.php b/app/cli.php index 09b3dc9413..6447de592b 100644 --- a/app/cli.php +++ b/app/cli.php @@ -29,4 +29,13 @@ $cli Console::log(App::getEnv('_APP_VERSION', 'UNKNOWN')); }); +$cli + ->error(function ($error) { + if(App::getEnv('_APP_ENV', 'development')) { + Console::error($error); + } else { + Console::error($error->getMessage()); + } + }); + $cli->run(); From f15d476889ceae5f561fc39fb76253b5416e55f9 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 16 Oct 2022 01:44:41 +0300 Subject: [PATCH 15/36] Fixed specification --- app/tasks/specs.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/tasks/specs.php b/app/tasks/specs.php index 755662bbc7..8d1bc5039f 100644 --- a/app/tasks/specs.php +++ b/app/tasks/specs.php @@ -9,8 +9,12 @@ use Appwrite\Specification\Specification; use Appwrite\Utopia\Response; use Swoole\Http\Response as HttpResponse; use Utopia\App; +use Utopia\Cache\Adapter\None; +use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Config\Config; +use Utopia\Database\Adapter\MySQL; +use Utopia\Database\Database; use Utopia\Request; use Utopia\Validator\WhiteList; @@ -19,16 +23,15 @@ $cli ->param('version', 'latest', new Text(16), 'Spec version', true) ->param('mode', 'normal', new WhiteList(['normal', 'mocks']), 'Spec Mode', true) ->action(function ($version, $mode) use ($register) { - $consoleDB = $register->get('dbPool')->getConsoleDB(); - $redis = $register->get('cache'); $appRoutes = App::getRoutes(); $response = new Response(new HttpResponse()); $mocks = ($mode === 'mocks'); + // Mock dependencies App::setResource('request', fn () => new Request()); App::setResource('response', fn () => $response); - App::setResource('consoleDB', fn () => $consoleDB); - App::setResource('cache', fn () => $redis); + App::setResource('dbForConsole', fn () => new Database(new MySQL(''), new Cache(new None()))); + App::setResource('dbForProject', fn () => new Database(new MySQL(''), new Cache(new None()))); $platforms = [ 'client' => APP_PLATFORM_CLIENT, From 8437aa894d53d91c506de96f63653add30b1d40e Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 16 Oct 2022 01:51:11 +0300 Subject: [PATCH 16/36] Removed unused imports --- app/workers/audits.php | 1 - app/workers/builds.php | 2 -- app/workers/certificates.php | 1 - 3 files changed, 4 deletions(-) diff --git a/app/workers/audits.php b/app/workers/audits.php index 24812c7dbf..90ac020536 100644 --- a/app/workers/audits.php +++ b/app/workers/audits.php @@ -1,6 +1,5 @@ Date: Sun, 16 Oct 2022 14:42:00 +0300 Subject: [PATCH 17/36] Added support for cache sharding, and fallback connections --- Dockerfile | 13 +++++- app/http.php | 3 +- app/init.php | 61 ++++++++++++++++--------- app/preload.php | 1 + composer.json | 4 +- composer.lock | 82 +++++++++++++++++----------------- src/Appwrite/Resque/Worker.php | 23 ++++++---- 7 files changed, 112 insertions(+), 75 deletions(-) diff --git a/Dockerfile b/Dockerfile index a7cae38502..410fb1c44c 100755 --- a/Dockerfile +++ b/Dockerfile @@ -35,6 +35,7 @@ ENV PHP_REDIS_VERSION=5.3.7 \ PHP_IMAGICK_VERSION=3.7.0 \ PHP_YAML_VERSION=2.2.2 \ PHP_MAXMINDDB_VERSION=v1.11.0 \ + PHP_MEMCACHED_VERSION=v3.2.0 \ PHP_ZSTD_VERSION="4504e4186e79b197cfcb75d4d09aa47ef7d92fe9 " RUN \ @@ -52,6 +53,7 @@ RUN \ imagemagick \ imagemagick-dev \ libmaxminddb-dev \ + libmemcached-dev \ zstd-dev RUN docker-php-ext-install sockets @@ -125,6 +127,15 @@ RUN \ ./configure && \ make && make install +# Memcached Extension +FROM compile as memcached +RUN \ + git clone --depth 1 --branch $PHP_MEMCACHED_VERSION https://github.com/php-memcached-dev/php-memcached.git && \ + cd php-memcached && \ + phpize && \ + ./configure && \ + make && make install + # Zstd Compression FROM compile as zstd RUN git clone --recursive -n https://github.com/kjdev/php-ext-zstd.git \ @@ -134,7 +145,6 @@ RUN git clone --recursive -n https://github.com/kjdev/php-ext-zstd.git \ && ./configure --with-libzstd \ && make && make install - # Rust Extensions Compile Image FROM php:8.0.18-cli as rust_compile @@ -304,6 +314,7 @@ COPY --from=imagick /usr/local/lib/php/extensions/no-debug-non-zts-20200930/imag COPY --from=yaml /usr/local/lib/php/extensions/no-debug-non-zts-20200930/yaml.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ COPY --from=maxmind /usr/local/lib/php/extensions/no-debug-non-zts-20200930/maxminddb.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ COPY --from=mongodb /usr/local/lib/php/extensions/no-debug-non-zts-20200930/mongodb.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ +COPY --from=memcached /usr/local/lib/php/extensions/no-debug-non-zts-20200930/memcached.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ COPY --from=scrypt /usr/local/lib/php/extensions/php-scrypt/target/libphp_scrypt.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ COPY --from=zstd /usr/local/lib/php/extensions/no-debug-non-zts-20200930/zstd.so /usr/local/lib/php/extensions/no-debug-non-zts-20200930/ diff --git a/app/http.php b/app/http.php index 769ffc117e..fca4ff5c60 100644 --- a/app/http.php +++ b/app/http.php @@ -90,7 +90,8 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) { $collections = Config::getParam('collections', []); try { - // $redis->flushAll(); + $cache = $app->getResource('cache'); /** @var Utopia\Cache\Cache $cache */ + $cache->flush(); Console::success('[Setup] - Creating database: appwrite...'); $dbForConsole->create(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); } catch (\Exception $e) { diff --git a/app/init.php b/app/init.php index 305d128145..28bba7af26 100644 --- a/app/init.php +++ b/app/init.php @@ -18,8 +18,6 @@ ini_set('display_startup_errors', 1); ini_set('default_socket_timeout', -1); error_reporting(E_ALL); -use Ahc\Jwt\JWT; -use Ahc\Jwt\JWTException; use Appwrite\Extend\Exception; use Appwrite\Auth\Auth; use Appwrite\SMS\Adapter\Mock; @@ -39,6 +37,7 @@ use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\IP; use Appwrite\Network\Validator\URL; use Appwrite\OpenSSL\OpenSSL; +use Appwrite\URL\URL as URLURL; use Appwrite\Usage\Stats; use Appwrite\Utopia\View; use Utopia\App; @@ -63,18 +62,19 @@ use Utopia\Storage\Device\Local; use Utopia\Storage\Device\S3; use Utopia\Storage\Device\Linode; use Utopia\Storage\Device\Wasabi; -use MaxMind\Db\Reader; -use PHPMailer\PHPMailer\PHPMailer; -use Swoole\Database\PDOProxy; -use Utopia\Cache\Adapter\None; use Utopia\Cache\Adapter\Redis as RedisCache; +use Utopia\Cache\Adapter\Sharding; use Utopia\Cache\Cache; use Utopia\CLI\Console; use Utopia\Database\Adapter\MariaDB; use Utopia\Database\Adapter\MySQL; -use Utopia\Pools\Connection; use Utopia\Pools\Group; use Utopia\Pools\Pool; +use Ahc\Jwt\JWT; +use Ahc\Jwt\JWTException; +use MaxMind\Db\Reader; +use PHPMailer\PHPMailer\PHPMailer; +use Swoole\Database\PDOProxy; const APP_NAME = 'Appwrite'; const APP_DOMAIN = 'appwrite.io'; @@ -501,35 +501,50 @@ $register->set('pools', function () { $group= new Group(); + $fallbackForDB = URLURL::unparse([ + 'scheme' => 'mariadb', + 'host' => App::getEnv('_APP_DB_HOST', 'mariadb'), + 'port' => App::getEnv('_APP_DB_PORT', '3306'), + 'user' => App::getEnv('_APP_DB_USER', ''), + 'pass' => App::getEnv('_APP_DB_PASS', ''), + ]); + $fallbackForRedis = URLURL::unparse([ + 'scheme' => 'redis', + 'host' => App::getEnv('_APP_REDIS_HOST', 'redis'), + 'port' => App::getEnv('_APP_REDIS_PORT', '6379'), + 'user' => App::getEnv('_APP_REDIS_USER', ''), + 'pass' => App::getEnv('_APP_REDIS_PASS', ''), + ]); + $connections = [ 'console' => [ 'type' => 'database', - 'dsns' => App::getEnv('_APP_CONNECTIONS_DB_CONSOLE', ''), + 'dsns' => App::getEnv('_APP_CONNECTIONS_DB_CONSOLE', $fallbackForDB), 'multiple' => false, 'schemes' => ['mariadb', 'mysql'], ], 'database' => [ 'type' => 'database', - 'dsns' => App::getEnv('_APP_CONNECTIONS_DB_PROJECT', ''), + 'dsns' => App::getEnv('_APP_CONNECTIONS_DB_PROJECT', $fallbackForDB), 'multiple' => true, 'schemes' => ['mariadb', 'mysql'], ], 'queue' => [ 'type' => 'queue', - 'dsns' => App::getEnv('_APP_CONNECTIONS_QUEUE', ''), + 'dsns' => App::getEnv('_APP_CONNECTIONS_QUEUE', $fallbackForRedis), 'multiple' => false, 'schemes' => ['redis'], ], 'pubsub' => [ 'type' => 'pubsub', - 'dsns' => App::getEnv('_APP_CONNECTIONS_PUBSUB', ''), + 'dsns' => App::getEnv('_APP_CONNECTIONS_PUBSUB', $fallbackForRedis), 'multiple' => false, 'schemes' => ['redis'], ], 'cache' => [ 'type' => 'cache', - 'dsns' => App::getEnv('_APP_CONNECTIONS_CACHE', ''), - 'multiple' => false, // TODO add cache sharding + 'dsns' => App::getEnv('_APP_CONNECTIONS_CACHE', $fallbackForRedis), + 'multiple' => true, 'schemes' => ['redis'], ], ]; @@ -666,7 +681,7 @@ $register->set('influxdb', function () { return $client; }); $register->set('statsd', function () { - // Register DB connection + // Register DB connection $host = App::getEnv('_APP_STATSD_HOST', 'telegraf'); $port = App::getEnv('_APP_STATSD_PORT', 8125); @@ -1037,14 +1052,18 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) { }, ['pools', 'cache']); App::setResource('cache', function (Group $pools) { - $cacheAdapter = $pools - ->get('cache') - ->pop() - ->getResource() - ; + $list = Config::getParam('pools-cache', []); + $adapters = []; + + foreach ($list as $value) { + $adapters[] = $pools + ->get($value) + ->pop() + ->getResource() + ; + } - return new Cache(new None()); - return new Cache($cacheAdapter); + return new Cache(new Sharding($adapters)); }, ['pools']); App::setResource('deviceLocal', function () { diff --git a/app/preload.php b/app/preload.php index bf8b0bfd1d..4935db3da4 100644 --- a/app/preload.php +++ b/app/preload.php @@ -35,6 +35,7 @@ foreach ( realpath(__DIR__ . '/../vendor/symfony'), realpath(__DIR__ . '/../vendor/mongodb'), realpath(__DIR__ . '/../vendor/utopia-php/websocket'), // TODO: remove workerman autoload + realpath(__DIR__ . '/../vendor/utopia-php/cache'), // TODO: remove memcached autoload ] as $key => $value ) { if ($value !== false) { diff --git a/composer.json b/composer.json index 80fbd1ccba..e433cdb22e 100644 --- a/composer.json +++ b/composer.json @@ -48,10 +48,10 @@ "utopia-php/abuse": "0.14.*", "utopia-php/analytics": "0.2.*", "utopia-php/audit": "0.15.*", - "utopia-php/cache": "0.6.*", + "utopia-php/cache": "0.7.*", "utopia-php/cli": "0.13.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.26.*", + "utopia-php/database": "dev-feat-update-cache-lib as 0.26.1", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", diff --git a/composer.lock b/composer.lock index bf43a6e162..7494bccd2d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "08fdd139ad1285b02c4b4e555679e7de", + "content-hash": "030dfcfbea2caebad080edbf048b87cf", "packages": [ { "name": "adhocore/jwt", @@ -1897,24 +1897,26 @@ }, { "name": "utopia-php/cache", - "version": "0.6.1", + "version": "0.7.0", "source": { "type": "git", "url": "https://github.com/utopia-php/cache.git", - "reference": "9889235a6d3da6cbb1f435201529da4d27c30e79" + "reference": "cd53431242c88299daea2589e21322abe97682cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/cache/zipball/9889235a6d3da6cbb1f435201529da4d27c30e79", - "reference": "9889235a6d3da6cbb1f435201529da4d27c30e79", + "url": "https://api.github.com/repos/utopia-php/cache/zipball/cd53431242c88299daea2589e21322abe97682cc", + "reference": "cd53431242c88299daea2589e21322abe97682cc", "shasum": "" }, "require": { "ext-json": "*", + "ext-memcached": "*", "ext-redis": "*", "php": ">=8.0" }, "require-dev": { + "laravel/pint": "1.2.*", "phpunit/phpunit": "^9.3", "vimeo/psalm": "4.13.1" }, @@ -1928,12 +1930,6 @@ "license": [ "MIT" ], - "authors": [ - { - "name": "Eldad Fux", - "email": "eldad@appwrite.io" - } - ], "description": "A simple cache library to manage application cache storing, loading and purging", "keywords": [ "cache", @@ -1944,9 +1940,9 @@ ], "support": { "issues": "https://github.com/utopia-php/cache/issues", - "source": "https://github.com/utopia-php/cache/tree/0.6.1" + "source": "https://github.com/utopia-php/cache/tree/0.7.0" }, - "time": "2022-08-10T08:12:46+00:00" + "time": "2022-10-16T06:04:12+00:00" }, { "name": "utopia-php/cli", @@ -2054,16 +2050,16 @@ }, { "name": "utopia-php/database", - "version": "0.26.0", + "version": "dev-feat-update-cache-lib", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "d172af2541137c83a86d066f82f48914b5a3a610" + "reference": "1ebee3c10a6112ab5665681f2d64f7381d3218b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/d172af2541137c83a86d066f82f48914b5a3a610", - "reference": "d172af2541137c83a86d066f82f48914b5a3a610", + "url": "https://api.github.com/repos/utopia-php/database/zipball/1ebee3c10a6112ab5665681f2d64f7381d3218b2", + "reference": "1ebee3c10a6112ab5665681f2d64f7381d3218b2", "shasum": "" }, "require": { @@ -2072,7 +2068,7 @@ "ext-redis": "*", "mongodb/mongodb": "1.8.0", "php": ">=8.0", - "utopia-php/cache": "0.6.*", + "utopia-php/cache": "0.7.*", "utopia-php/framework": "0.*.*" }, "require-dev": { @@ -2092,16 +2088,6 @@ "license": [ "MIT" ], - "authors": [ - { - "name": "Eldad Fux", - "email": "eldad@appwrite.io" - }, - { - "name": "Brandon Leckemby", - "email": "brandon@appwrite.io" - } - ], "description": "A simple library to manage application persistency using multiple database adapters", "keywords": [ "database", @@ -2112,9 +2098,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.26.0" + "source": "https://github.com/utopia-php/database/tree/feat-update-cache-lib" }, - "time": "2022-10-03T17:12:01+00:00" + "time": "2022-10-16T09:47:14+00:00" }, { "name": "utopia-php/domains", @@ -3466,25 +3452,30 @@ }, { "name": "phpdocumentor/type-resolver", - "version": "1.6.1", + "version": "1.6.2", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "77a32518733312af16a44300404e945338981de3" + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", - "reference": "77a32518733312af16a44300404e945338981de3", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d", + "reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", + "php": "^7.4 || ^8.0", "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { "ext-tokenizer": "*", - "psalm/phar": "^4.8" + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" }, "type": "library", "extra": { @@ -3510,9 +3501,9 @@ "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", "support": { "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1" + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2" }, - "time": "2022-03-15T21:29:03+00:00" + "time": "2022-10-14T12:47:21+00:00" }, { "name": "phpspec/prophecy", @@ -5405,9 +5396,18 @@ "time": "2022-09-28T08:42:51+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/database", + "version": "dev-feat-update-cache-lib", + "alias": "0.26.1", + "alias_normalized": "0.26.1.0" + } + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "utopia-php/database": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -5431,5 +5431,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.3.0" } diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index 1af433042c..28e7106b7e 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -4,8 +4,9 @@ namespace Appwrite\Resque; use Exception; use Utopia\App; -use Utopia\Cache\Adapter\None; use Utopia\Cache\Cache; +use Utopia\Config\Config; +use Utopia\Cache\Adapter\Sharding; use Utopia\Database\Database; use Utopia\Storage\Device; use Utopia\Storage\Storage; @@ -226,14 +227,18 @@ abstract class Worker $pools = $register->get('pools'); /* @var \Utopia\Pools\Group $pools */ - $pools - ->get('cache') - ->pop() - ->getResource() - ; - - return new Cache(new None()); - // return new Cache($cacheAdapter); + $list = Config::getParam('pools-cache', []); + $adapters = []; + + foreach ($list as $value) { + $adapters[] = $pools + ->get($value) + ->pop() + ->getResource() + ; + } + + return new Cache(new Sharding($adapters)); } /** From fa0216cd6d4a4fe6dc341d33ee7e9aa79311f9e1 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 16 Oct 2022 14:53:31 +0300 Subject: [PATCH 18/36] Removed legacy connection push --- app/http.php | 7 ------- app/realtime.php | 4 ---- 2 files changed, 11 deletions(-) diff --git a/app/http.php b/app/http.php index fca4ff5c60..bfd7e7581c 100644 --- a/app/http.php +++ b/app/http.php @@ -316,13 +316,6 @@ $http->on('request', function (SwooleRequest $swooleRequest, SwooleResponse $swo Console::error('[Error] File: ' . $th->getFile()); Console::error('[Error] Line: ' . $th->getLine()); - /** - * Reset Database connection if PDOException was thrown. - */ - if ($th instanceof PDOException) { - $db = null; - } - $swooleResponse->setStatusCode(500); $output = ((App::isDevelopment())) ? [ diff --git a/app/realtime.php b/app/realtime.php index 9df6ed5e4f..cea2f89b68 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -456,10 +456,6 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, Console::error('[Error] Code: ' . $response['data']['code']); Console::error('[Error] Message: ' . $response['data']['message']); } - - if ($th instanceof PDOException) { - $db = null; - } } finally { /** * Put used PDO and Redis Connections back into their pools. From fe29e58f22b523ff5ac8cdb261027ea97c1b7e78 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Sun, 16 Oct 2022 20:48:53 +0300 Subject: [PATCH 19/36] Fixed doctor health checks --- app/controllers/api/projects.php | 2 +- app/init.php | 4 -- app/tasks/doctor.php | 85 ++++++++++++++++++++------------ composer.json | 2 +- composer.lock | 24 ++++----- 5 files changed, 68 insertions(+), 49 deletions(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 061a764112..ae4491bbb8 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -73,7 +73,7 @@ App::post('/v1/projects') ->inject('dbForConsole') ->inject('cache') ->inject('pools') - ->action(function (string $projectId, string $name, string $teamId, string $region, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Cache $cache, Group $pools) { + ->action(function (string $projectId, string $name, string $teamId, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Cache $cache, Group $pools) { $team = $dbForConsole->getDocument('teams', $teamId); if ($team->isEmpty()) { diff --git a/app/init.php b/app/init.php index 28bba7af26..c97745eccc 100644 --- a/app/init.php +++ b/app/init.php @@ -658,11 +658,7 @@ $register->set('pools', function () { Config::setParam('pools-'.$key, $config); } - Console::log('Filling pools...'); - $group->fill(); - - Console::success('Pools are ready.'); return $group; }); diff --git a/app/tasks/doctor.php b/app/tasks/doctor.php index 6875b65092..3019b91279 100644 --- a/app/tasks/doctor.php +++ b/app/tasks/doctor.php @@ -8,6 +8,7 @@ use Utopia\Storage\Device\Local; use Utopia\Storage\Storage; use Utopia\App; use Utopia\CLI\Console; +use Utopia\Config\Config; use Utopia\Domains\Domain; $cli @@ -21,7 +22,7 @@ $cli Console::log("\n" . '👩‍⚕️ Running ' . APP_NAME . ' Doctor for version ' . App::getEnv('_APP_VERSION', 'UNKNOWN') . ' ...' . "\n"); - Console::log('Checking for production best practices...'); + Console::log('[Settings]'); $domain = new Domain(App::getEnv('_APP_DOMAIN')); @@ -90,32 +91,54 @@ $cli \sleep(0.2); try { - Console::log("\n" . 'Checking connectivity...'); + Console::log("\n" . '[Connectivity]'); } catch (\Throwable $th) { //throw $th; } - try { - $dbPool = $register->get('dbPool'); /* @var $dbPool Pools */ - $database = $dbPool->getConsoleDB(); - $pdo = $dbPool->getPDO($database); - Console::success('Database............connected 👍'); - } catch (\Throwable $th) { - Console::error('Database.........disconnected 👎'); + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + $configs = [ + 'Console.DB' => Config::getParam('pools-console'), + 'Projects.DB' => Config::getParam('pools-database'), + ]; + + foreach ($configs as $key => $config) { + foreach ($config as $database) { + $adapter = $pools->get($database)->pop()->getResource(); + + try { + if($adapter->ping()) { + Console::success('🟢 '.str_pad("{$key}({$database})", 50, '.').'connected'); + } else { + Console::error('🔴 '.str_pad("{$key}({$database})", 47, '.').'disconnected'); + } + } catch (\Throwable $th) { + Console::error('🔴 '.str_pad("{$key}.({$database})", 47, '.').'disconnected'); + } + } } - try { - $register->get('cache'); - Console::success('Queue...............connected 👍'); - } catch (\Throwable $th) { - Console::error('Queue............disconnected 👎'); - } + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + $configs = [ + 'Cache' => Config::getParam('pools-cache'), + 'Queue' => Config::getParam('pools-queue'), + 'PubSub' => Config::getParam('pools-pubsub'), + ]; - try { - $register->get('cache'); - Console::success('Cache...............connected 👍'); - } catch (\Throwable $th) { - Console::error('Cache............disconnected 👎'); + foreach ($configs as $key => $config) { + foreach ($config as $pool) { + $adapter = $pools->get($pool)->pop()->getResource(); + + try { + if($adapter->ping()) { + Console::success('🟢 '.str_pad("{$key}({$pool})", 50, '.').'connected'); + } else { + Console::error('🔴 '.str_pad("{$key}({$pool})", 47, '.').'disconnected'); + } + } catch (\Throwable $th) { + Console::error('🔴 '.str_pad("{$key}({$pool})", 47, '.').'disconnected'); + } + } } if (App::getEnv('_APP_STORAGE_ANTIVIRUS') === 'enabled') { // Check if scans are enabled @@ -126,12 +149,12 @@ $cli ); if ((@$antivirus->ping())) { - Console::success('Antivirus...........connected 👍'); + Console::success('🟢 '.str_pad("Antivirus", 50, '.').'connected'); } else { - Console::error('Antivirus........disconnected 👎'); + Console::error('🔴 '.str_pad("Antivirus", 47, '.').'disconnected'); } } catch (\Throwable $th) { - Console::error('Antivirus........disconnected 👎'); + Console::error('🔴 '.str_pad("Antivirus", 47, '.').'disconnected'); } } @@ -144,35 +167,35 @@ $cli $mail->AltBody = 'Hello World'; $mail->send(); - Console::success('SMTP................connected 👍'); + Console::success('🟢 '.str_pad("SMTP", 50, '.').'connected'); } catch (\Throwable $th) { - Console::error('SMTP.............disconnected 👎'); + Console::error('🔴 '.str_pad("SMTP", 47, '.').'disconnected'); } $host = App::getEnv('_APP_STATSD_HOST', 'telegraf'); $port = App::getEnv('_APP_STATSD_PORT', 8125); if ($fp = @\fsockopen('udp://' . $host, $port, $errCode, $errStr, 2)) { - Console::success('StatsD..............connected 👍'); + Console::success('🟢 '.str_pad("StatsD", 50, '.').'connected'); \fclose($fp); } else { - Console::error('StatsD...........disconnected 👎'); + Console::error('🔴 '.str_pad("StatsD", 47, '.').'disconnected'); } $host = App::getEnv('_APP_INFLUXDB_HOST', ''); $port = App::getEnv('_APP_INFLUXDB_PORT', ''); if ($fp = @\fsockopen($host, $port, $errCode, $errStr, 2)) { - Console::success('InfluxDB............connected 👍'); + Console::success('🟢 '.str_pad("InfluxDB", 50, '.').'connected'); \fclose($fp); } else { - Console::error('InfluxDB.........disconnected 👎'); + Console::error('🔴 '.str_pad("InfluxDB", 47, '.').'disconnected'); } \sleep(0.2); Console::log(''); - Console::log('Checking volumes...'); + Console::log('[Volumes]'); foreach ( [ @@ -200,7 +223,7 @@ $cli \sleep(0.2); Console::log(''); - Console::log('Checking disk space usage...'); + Console::log('[Disk Space]'); foreach ( [ diff --git a/composer.json b/composer.json index e433cdb22e..e09bec422e 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,7 @@ "utopia-php/abuse": "0.14.*", "utopia-php/analytics": "0.2.*", "utopia-php/audit": "0.15.*", - "utopia-php/cache": "0.7.*", + "utopia-php/cache": "0.8.*", "utopia-php/cli": "0.13.*", "utopia-php/config": "0.2.*", "utopia-php/database": "dev-feat-update-cache-lib as 0.26.1", diff --git a/composer.lock b/composer.lock index 7494bccd2d..28d48b7f3d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "030dfcfbea2caebad080edbf048b87cf", + "content-hash": "f3beee3a829a19e53b311052111bde2c", "packages": [ { "name": "adhocore/jwt", @@ -1897,16 +1897,16 @@ }, { "name": "utopia-php/cache", - "version": "0.7.0", + "version": "0.8.0", "source": { "type": "git", "url": "https://github.com/utopia-php/cache.git", - "reference": "cd53431242c88299daea2589e21322abe97682cc" + "reference": "212e66100a1f32e674fca5d9bc317cc998303089" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/cache/zipball/cd53431242c88299daea2589e21322abe97682cc", - "reference": "cd53431242c88299daea2589e21322abe97682cc", + "url": "https://api.github.com/repos/utopia-php/cache/zipball/212e66100a1f32e674fca5d9bc317cc998303089", + "reference": "212e66100a1f32e674fca5d9bc317cc998303089", "shasum": "" }, "require": { @@ -1940,9 +1940,9 @@ ], "support": { "issues": "https://github.com/utopia-php/cache/issues", - "source": "https://github.com/utopia-php/cache/tree/0.7.0" + "source": "https://github.com/utopia-php/cache/tree/0.8.0" }, - "time": "2022-10-16T06:04:12+00:00" + "time": "2022-10-16T16:48:09+00:00" }, { "name": "utopia-php/cli", @@ -2054,12 +2054,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "1ebee3c10a6112ab5665681f2d64f7381d3218b2" + "reference": "44ae47dfd49c9c7c0cba29f6867347e25c23b57b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/1ebee3c10a6112ab5665681f2d64f7381d3218b2", - "reference": "1ebee3c10a6112ab5665681f2d64f7381d3218b2", + "url": "https://api.github.com/repos/utopia-php/database/zipball/44ae47dfd49c9c7c0cba29f6867347e25c23b57b", + "reference": "44ae47dfd49c9c7c0cba29f6867347e25c23b57b", "shasum": "" }, "require": { @@ -2068,7 +2068,7 @@ "ext-redis": "*", "mongodb/mongodb": "1.8.0", "php": ">=8.0", - "utopia-php/cache": "0.7.*", + "utopia-php/cache": "0.8.*", "utopia-php/framework": "0.*.*" }, "require-dev": { @@ -2100,7 +2100,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/feat-update-cache-lib" }, - "time": "2022-10-16T09:47:14+00:00" + "time": "2022-10-16T17:35:26+00:00" }, { "name": "utopia-php/domains", From f6449687b5e34c140a5c033fd6e49b6ba46886f5 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 17 Oct 2022 01:49:53 +0300 Subject: [PATCH 20/36] Create connections only on fill method --- app/init.php | 103 +++++++++++++++++++++++-------------------- app/tasks/doctor.php | 10 ++--- 2 files changed, 60 insertions(+), 53 deletions(-) diff --git a/app/init.php b/app/init.php index c97745eccc..34a2db923e 100644 --- a/app/init.php +++ b/app/init.php @@ -590,24 +590,30 @@ $register->set('pools', function () { switch ($dsn->getScheme()) { case 'mysql': case 'mariadb': - $resource = new PDOProxy(function() use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnScheme) { - return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnScheme};charset=utf8mb4", $dsnUser, $dsnPass, array( - PDO::ATTR_TIMEOUT => 3, // Seconds - PDO::ATTR_PERSISTENT => true, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed - PDO::ATTR_EMULATE_PREPARES => true, - PDO::ATTR_STRINGIFY_FETCHES => true - )); - }); + $resource = function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnScheme) { + return new PDOProxy(function() use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnScheme) { + return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnScheme};charset=utf8mb4", $dsnUser, $dsnPass, array( + PDO::ATTR_TIMEOUT => 3, // Seconds + PDO::ATTR_PERSISTENT => true, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_ERRMODE => App::isDevelopment() ? PDO::ERRMODE_WARNING : PDO::ERRMODE_SILENT, // If in production mode, warnings are not displayed + PDO::ATTR_EMULATE_PREPARES => true, + PDO::ATTR_STRINGIFY_FETCHES => true + )); + }); + }; break; case 'redis': - $resource = new Redis(); - $resource->pconnect($dsnHost, $dsnPort); - if($dsnPass) { - $resource->auth($dsnPass); - } - $resource->setOption(Redis::OPT_READ_TIMEOUT, -1); + $resource = function() use ($dsnHost, $dsnPort, $dsnPass) { + $redis = new Redis(); + @$redis->pconnect($dsnHost, $dsnPort); + if($dsnPass) { + $redis->auth($dsnPass); + } + $redis->setOption(Redis::OPT_READ_TIMEOUT, -1); + + return $redis; + }; break; default: @@ -615,40 +621,37 @@ $register->set('pools', function () { break; } - // Get Adapter + $pool = new Pool($name, 64, function () use ($type, $resource, $dsn) { + // Get Adapter + $adapter = null; - switch ($type) { - case 'database': - $adapter = match ($dsn->getScheme()) { - 'mariadb' => new MariaDB($resource), - 'mysql' => new MySQL($resource), - default => null - }; + switch ($type) { + case 'database': + $adapter = match ($dsn->getScheme()) { + 'mariadb' => new MariaDB($resource()), + 'mysql' => new MySQL($resource()), + default => null + }; + + break; + case 'queue': + //$adapter = new Queue($resource); + break; + case 'pubsub': + //$adapter = new PubSub($resource); + break; + case 'cache': + $adapter = match ($dsn->getScheme()) { + 'redis' => new RedisCache($resource()), + default => null + }; + break; - break; - case 'queue': - //$adapter = new Queue($resource); - break; - case 'pubsub': - //$adapter = new PubSub($resource); - break; - case 'cache': - $adapter = match ($dsn->getScheme()) { - 'redis' => new RedisCache($resource), - default => null - }; - break; + default: + throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation."); + break; + } - default: - throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation."); - break; - } - - if(is_null($adapter)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation."); - } - - $pool = new Pool($name, 64, function () use ($adapter) { return $adapter; }); @@ -658,7 +661,11 @@ $register->set('pools', function () { Config::setParam('pools-'.$key, $config); } - $group->fill(); + try { + $group->fill(); + } catch (\Throwable $th) { + Console::error('Connection failure: '.$th->getMessage()); + } return $group; }); diff --git a/app/tasks/doctor.php b/app/tasks/doctor.php index 3019b91279..b1a47fdb26 100644 --- a/app/tasks/doctor.php +++ b/app/tasks/doctor.php @@ -78,7 +78,6 @@ $cli Console::log('🟢 HTTPS force option is enabled'); } - $providerName = App::getEnv('_APP_LOGGING_PROVIDER', ''); $providerConfig = App::getEnv('_APP_LOGGING_CONFIG', ''); @@ -97,6 +96,7 @@ $cli } $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + $configs = [ 'Console.DB' => Config::getParam('pools-console'), 'Projects.DB' => Config::getParam('pools-database'), @@ -104,9 +104,9 @@ $cli foreach ($configs as $key => $config) { foreach ($config as $database) { - $adapter = $pools->get($database)->pop()->getResource(); - try { + $adapter = $pools->get($database)->pop()->getResource(); + if($adapter->ping()) { Console::success('🟢 '.str_pad("{$key}({$database})", 50, '.').'connected'); } else { @@ -127,9 +127,9 @@ $cli foreach ($configs as $key => $config) { foreach ($config as $pool) { - $adapter = $pools->get($pool)->pop()->getResource(); - try { + $adapter = $pools->get($pool)->pop()->getResource(); + if($adapter->ping()) { Console::success('🟢 '.str_pad("{$key}({$pool})", 50, '.').'connected'); } else { From 65e004f145c2d11236bc9c01d3c9a4fca14a18f9 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 17 Oct 2022 14:43:57 +0300 Subject: [PATCH 21/36] Fixed health API and add new test endpoints --- app/controllers/api/health.php | 233 +++++++++++++++--- app/init.php | 4 +- docs/references/health/get-cache.md | 2 +- docs/references/health/get-db.md | 2 +- docs/references/health/get-pubsub.md | 1 + docs/references/health/get-queue.md | 1 + src/Appwrite/Utopia/Response.php | 2 + .../Utopia/Response/Model/HealthStatus.php | 6 + .../Health/HealthCustomServerTest.php | 56 ++++- 9 files changed, 260 insertions(+), 47 deletions(-) create mode 100644 docs/references/health/get-pubsub.md create mode 100644 docs/references/health/get-queue.md diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index 4842d3f528..1fdbf0fc1d 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -5,7 +5,9 @@ use Appwrite\Event\Event; use Appwrite\Extend\Exception; use Appwrite\Utopia\Response; use Utopia\App; +use Utopia\Config\Config; use Utopia\Database\Document; +use Utopia\Pools\Group; use Utopia\Registry\Registry; use Utopia\Storage\Device; use Utopia\Storage\Device\Local; @@ -26,6 +28,7 @@ App::get('/v1/health') ->action(function (Response $response) { $output = [ + 'name' => 'http', 'status' => 'pass', 'ping' => 0 ]; @@ -42,7 +45,6 @@ App::get('/v1/health/version') ->label('sdk.response.model', Response::MODEL_HEALTH_VERSION) ->inject('response') ->action(function (Response $response) { - $response->dynamic(new Document([ 'version' => APP_VERSION_STABLE ]), Response::MODEL_HEALTH_VERSION); }); @@ -58,33 +60,50 @@ App::get('/v1/health/db') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) ->inject('response') - ->inject('utopia') - ->action(function (Response $response, App $utopia) { + ->inject('pools') + ->action(function (Response $response, Group $pools) { - $checkStart = \microtime(true); + $output = []; - try { - $dbPool = $utopia->getResource('dbPool'); - $database = $dbPool->getConsoleDB(); - /* @var $consoleDB PDO */ - $consoleDB = $dbPool->getPDO($database); - - // Run a small test to check the connection - $statement = $consoleDB->prepare("SELECT 1;"); - - $statement->closeCursor(); - - $statement->execute(); - } catch (Exception $_e) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Database is not available'); - } - - $output = [ - 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + $configs = [ + 'Console.DB' => Config::getParam('pools-console'), + 'Projects.DB' => Config::getParam('pools-database'), ]; - $response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS); + foreach ($configs as $key => $config) { + foreach ($config as $database) { + try { + $adapter = $pools->get($database)->pop()->getResource(); + + $checkStart = \microtime(true); + + if($adapter->ping()) { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'pass', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } else { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'fail', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } + } catch (\Throwable $th) { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'fail', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } + } + } + + $response->dynamic(new Document([ + 'statuses' => $output, + 'total' => count($output), + ]), Response::MODEL_HEALTH_STATUS_LIST); }); App::get('/v1/health/cache') @@ -99,23 +118,163 @@ App::get('/v1/health/cache') ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) ->inject('response') - ->inject('utopia') - ->action(function (Response $response, App $utopia) { + ->inject('pools') + ->action(function (Response $response, Group $pools) { - $checkStart = \microtime(true); + $output = []; - $redis = $utopia->getResource('cache'); - - if (!$redis->ping(true)) { - throw new Exception(Exception::GENERAL_SERVER_ERROR, 'Cache is not available'); - } - - $output = [ - 'status' => 'pass', - 'ping' => \round((\microtime(true) - $checkStart) / 1000) + $configs = [ + 'Cache' => Config::getParam('pools-cache'), ]; - $response->dynamic(new Document($output), Response::MODEL_HEALTH_STATUS); + foreach ($configs as $key => $config) { + foreach ($config as $database) { + try { + $adapter = $pools->get($database)->pop()->getResource(); + + $checkStart = \microtime(true); + + if($adapter->ping()) { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'pass', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } else { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'fail', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } + } catch (\Throwable $th) { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'fail', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } + } + } + + $response->dynamic(new Document([ + 'statuses' => $output, + 'total' => count($output), + ]), Response::MODEL_HEALTH_STATUS_LIST); + }); + +App::get('/v1/health/queue') + ->desc('Get Queue') + ->groups(['api', 'health']) + ->label('scope', 'health.read') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'health') + ->label('sdk.method', 'getQueue') + ->label('sdk.description', '/docs/references/health/get-queue.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) + ->inject('response') + ->inject('pools') + ->action(function (Response $response, Group $pools) { + + $output = []; + + $configs = [ + 'Queue' => Config::getParam('pools-queue'), + ]; + + foreach ($configs as $key => $config) { + foreach ($config as $database) { + try { + $adapter = $pools->get($database)->pop()->getResource(); + + $checkStart = \microtime(true); + + if($adapter->ping()) { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'pass', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } else { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'fail', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } + } catch (\Throwable $th) { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'fail', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } + } + } + + $response->dynamic(new Document([ + 'statuses' => $output, + 'total' => count($output), + ]), Response::MODEL_HEALTH_STATUS_LIST); + }); + +App::get('/v1/health/pubsub') + ->desc('Get PubSub') + ->groups(['api', 'health']) + ->label('scope', 'health.read') + ->label('sdk.auth', [APP_AUTH_TYPE_KEY]) + ->label('sdk.namespace', 'health') + ->label('sdk.method', 'getPubSub') + ->label('sdk.description', '/docs/references/health/get-pubsub.md') + ->label('sdk.response.code', Response::STATUS_CODE_OK) + ->label('sdk.response.type', Response::CONTENT_TYPE_JSON) + ->label('sdk.response.model', Response::MODEL_HEALTH_STATUS) + ->inject('response') + ->inject('pools') + ->action(function (Response $response, Group $pools) { + + $output = []; + + $configs = [ + 'PubSub' => Config::getParam('pools-pubsub'), + ]; + + foreach ($configs as $key => $config) { + foreach ($config as $database) { + try { + $adapter = $pools->get($database)->pop()->getResource(); + + $checkStart = \microtime(true); + + if($adapter->ping()) { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'pass', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } else { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'fail', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } + } catch (\Throwable $th) { + $output[] = new Document([ + 'name' => $key." ($database)", + 'status' => 'fail', + 'ping' => \round((\microtime(true) - $checkStart) / 1000) + ]); + } + } + } + + $response->dynamic(new Document([ + 'statuses' => $output, + 'total' => count($output), + ]), Response::MODEL_HEALTH_STATUS_LIST); }); App::get('/v1/health/time') diff --git a/app/init.php b/app/init.php index 34a2db923e..9c813d8b98 100644 --- a/app/init.php +++ b/app/init.php @@ -635,10 +635,10 @@ $register->set('pools', function () { break; case 'queue': - //$adapter = new Queue($resource); + $adapter = $resource(); break; case 'pubsub': - //$adapter = new PubSub($resource); + $adapter = $resource(); break; case 'cache': $adapter = match ($dsn->getScheme()) { diff --git a/docs/references/health/get-cache.md b/docs/references/health/get-cache.md index 91abcd6bc5..632c02208d 100644 --- a/docs/references/health/get-cache.md +++ b/docs/references/health/get-cache.md @@ -1 +1 @@ -Check the Appwrite in-memory cache server is up and connection is successful. \ No newline at end of file +Check the Appwrite in-memory cache servers are up and connection is successful. \ No newline at end of file diff --git a/docs/references/health/get-db.md b/docs/references/health/get-db.md index 9652d0d3e3..7381e51f70 100644 --- a/docs/references/health/get-db.md +++ b/docs/references/health/get-db.md @@ -1 +1 @@ -Check the Appwrite database server is up and connection is successful. \ No newline at end of file +Check the Appwrite database servers are up and connection is successful. \ No newline at end of file diff --git a/docs/references/health/get-pubsub.md b/docs/references/health/get-pubsub.md new file mode 100644 index 0000000000..8f86411e8f --- /dev/null +++ b/docs/references/health/get-pubsub.md @@ -0,0 +1 @@ +Check the Appwrite pub-sub servers are up and connection is successful. \ No newline at end of file diff --git a/docs/references/health/get-queue.md b/docs/references/health/get-queue.md new file mode 100644 index 0000000000..e4558f941f --- /dev/null +++ b/docs/references/health/get-queue.md @@ -0,0 +1 @@ +Check the Appwrite queue messaging servers are up and connection is successful. \ No newline at end of file diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index e23335365a..07134c6ea9 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -207,6 +207,7 @@ class Response extends SwooleResponse public const MODEL_HEALTH_QUEUE = 'healthQueue'; public const MODEL_HEALTH_TIME = 'healthTime'; public const MODEL_HEALTH_ANTIVIRUS = 'healthAntivirus'; + public const MODEL_HEALTH_STATUS_LIST = 'healthStatusList'; // Deprecated public const MODEL_PERMISSIONS = 'permissions'; @@ -268,6 +269,7 @@ class Response extends SwooleResponse ->setModel(new BaseList('Phones List', self::MODEL_PHONE_LIST, 'phones', self::MODEL_PHONE)) ->setModel(new BaseList('Metric List', self::MODEL_METRIC_LIST, 'metrics', self::MODEL_METRIC, true, false)) ->setModel(new BaseList('Variables List', self::MODEL_VARIABLE_LIST, 'variables', self::MODEL_VARIABLE)) + ->setModel(new BaseList('Status List', self::MODEL_HEALTH_STATUS_LIST, 'statuses', self::MODEL_HEALTH_STATUS)) // Entities ->setModel(new Database()) ->setModel(new Collection()) diff --git a/src/Appwrite/Utopia/Response/Model/HealthStatus.php b/src/Appwrite/Utopia/Response/Model/HealthStatus.php index 23756de131..ba340107ac 100644 --- a/src/Appwrite/Utopia/Response/Model/HealthStatus.php +++ b/src/Appwrite/Utopia/Response/Model/HealthStatus.php @@ -10,6 +10,12 @@ class HealthStatus extends Model public function __construct() { $this + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Name of the service.', + 'default' => '', + 'example' => 'database', + ]) ->addRule('ping', [ 'type' => self::TYPE_INTEGER, 'description' => 'Duration in milliseconds how long the health check took.', diff --git a/tests/e2e/Services/Health/HealthCustomServerTest.php b/tests/e2e/Services/Health/HealthCustomServerTest.php index 47a2268e21..96c9bde5c7 100644 --- a/tests/e2e/Services/Health/HealthCustomServerTest.php +++ b/tests/e2e/Services/Health/HealthCustomServerTest.php @@ -47,9 +47,9 @@ class HealthCustomServerTest extends Scope ], $this->getHeaders()), []); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('pass', $response['body']['status']); - $this->assertIsInt($response['body']['ping']); - $this->assertLessThan(100, $response['body']['ping']); + $this->assertEquals('pass', $response['body']['statuses'][0]['status']); + $this->assertIsInt($response['body']['statuses'][0]['ping']); + $this->assertLessThan(100, $response['body']['statuses'][0]['ping']); /** * Test for FAILURE @@ -69,9 +69,53 @@ class HealthCustomServerTest extends Scope ], $this->getHeaders()), []); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals('pass', $response['body']['status']); - $this->assertIsInt($response['body']['ping']); - $this->assertLessThan(100, $response['body']['ping']); + $this->assertEquals('pass', $response['body']['statuses'][0]['status']); + $this->assertIsInt($response['body']['statuses'][0]['ping']); + $this->assertLessThan(100, $response['body']['statuses'][0]['ping']); + + /** + * Test for FAILURE + */ + + return []; + } + + public function testQueueSuccess(): array + { + /** + * Test for SUCCESS + */ + $response = $this->client->call(Client::METHOD_GET, '/health/queue', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('pass', $response['body']['statuses'][0]['status']); + $this->assertIsInt($response['body']['statuses'][0]['ping']); + $this->assertLessThan(100, $response['body']['statuses'][0]['ping']); + + /** + * Test for FAILURE + */ + + return []; + } + + public function testPubSubSuccess(): array + { + /** + * Test for SUCCESS + */ + $response = $this->client->call(Client::METHOD_GET, '/health/pubsub', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), []); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals('pass', $response['body']['statuses'][0]['status']); + $this->assertIsInt($response['body']['statuses'][0]['ping']); + $this->assertLessThan(100, $response['body']['statuses'][0]['ping']); /** * Test for FAILURE From 2e23721774b68af00bd3254fd2d21f32b1313bdf Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 17 Oct 2022 15:46:56 +0300 Subject: [PATCH 22/36] Fixed maintenance container --- app/tasks/maintenance.php | 64 +++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/app/tasks/maintenance.php b/app/tasks/maintenance.php index 8d684d8bed..d7a4de77a6 100644 --- a/app/tasks/maintenance.php +++ b/app/tasks/maintenance.php @@ -7,7 +7,11 @@ use Appwrite\Database\Pools; use Appwrite\Event\Certificate; use Appwrite\Event\Delete; use Utopia\App; +use Utopia\Cache\Adapter\Sharding; +use Utopia\Cache\Cache; use Utopia\CLI\Console; +use Utopia\Config\Config; +use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\DateTime; use Utopia\Database\Query; @@ -106,6 +110,54 @@ $cli ->trigger(); } + /** + * Get console database + * @return Database + */ + function getConsoleDB(): Database + { + global $register; + + $pools = $register->get('pools'); /* @var \Utopia\Pools\Group $pools */ + + $dbAdapter = $pools + ->get('console') + ->pop() + ->getResource() + ; + + $database = new Database($dbAdapter, getCache()); + + $database->setNamespace('console'); + $database->setDefaultDatabase('appwrite'); + + return $database; + } + + /** + * Get Cache + * @return Cache + */ + function getCache(): Cache + { + global $register; + + $pools = $register->get('pools'); /* @var \Utopia\Pools\Group $pools */ + + $list = Config::getParam('pools-cache', []); + $adapters = []; + + foreach ($list as $value) { + $adapters[] = $pools + ->get($value) + ->pop() + ->getResource() + ; + } + + return new Cache(new Sharding($adapters)); + } + // # of days in seconds (1 day = 86400s) $interval = (int) App::getEnv('_APP_MAINTENANCE_INTERVAL', '86400'); $executionLogsRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', '1209600'); @@ -115,16 +167,8 @@ $cli $usageStatsRetention1d = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_USAGE_1D', '8640000'); // 100 days $cacheRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_CACHE', '2592000'); // 30 days - Console::loop(function () use ($register, $interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention, $usageStatsRetention30m, $usageStatsRetention1d, $cacheRetention) { - $redis = $register->get('cache'); - $dbPool = $register->get('dbPool'); - - $database = $dbPool->getConsoleDB(); - $pdo = $dbPool->getPDO($database); - $database = Pools::wait( - Pools::getDatabase($pdo, $redis, '_console'), - 'certificates', - ); + Console::loop(function () use ($interval, $executionLogsRetention, $abuseLogsRetention, $auditLogRetention, $usageStatsRetention30m, $usageStatsRetention1d, $cacheRetention) { + $database = getConsoleDB(); $time = DateTime::now(); From bef62ddc7161fae154ff2df817cd7c5a3abd4354 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 17 Oct 2022 15:47:07 +0300 Subject: [PATCH 23/36] Fixed DSN test --- src/Appwrite/DSN/DSN.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/DSN/DSN.php b/src/Appwrite/DSN/DSN.php index 11a25d5b18..f886d40211 100644 --- a/src/Appwrite/DSN/DSN.php +++ b/src/Appwrite/DSN/DSN.php @@ -58,7 +58,7 @@ class DSN $this->user = $parts['user'] ?? null; $this->password = $parts['pass'] ?? null; $this->host = $parts['host'] ?? null; - $this->port = (int)$parts['port'] ?? null; + $this->port = $parts['port'] ?? null; $this->database = $parts['path'] ?? null; $this->query = $parts['query'] ?? null; } @@ -110,7 +110,7 @@ class DSN */ public function getPort(): ?int { - return $this->port; + return (int)$this->port; } /** From 892f74c2a8f0ac9331c90ec95c5629cc74e49d10 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 17 Oct 2022 19:43:26 +0300 Subject: [PATCH 24/36] Fix DSN test --- src/Appwrite/DSN/DSN.php | 8 ++++---- tests/unit/DSN/DSNTest.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Appwrite/DSN/DSN.php b/src/Appwrite/DSN/DSN.php index f886d40211..03f4759387 100644 --- a/src/Appwrite/DSN/DSN.php +++ b/src/Appwrite/DSN/DSN.php @@ -27,7 +27,7 @@ class DSN /** * @var ?int */ - protected ?int $port; + protected ?string $port; /** * @var ?string @@ -106,11 +106,11 @@ class DSN /** * Return the port * - * @return ?int + * @return ?string */ - public function getPort(): ?int + public function getPort(): ?string { - return (int)$this->port; + return $this->port; } /** diff --git a/tests/unit/DSN/DSNTest.php b/tests/unit/DSN/DSNTest.php index 6565e0da19..d1f5ba1197 100644 --- a/tests/unit/DSN/DSNTest.php +++ b/tests/unit/DSN/DSNTest.php @@ -14,7 +14,7 @@ class DSNTest extends TestCase $this->assertEquals("user", $dsn->getUser()); $this->assertEquals("password", $dsn->getPassword()); $this->assertEquals("localhost", $dsn->getHost()); - $this->assertEquals(3306, $dsn->getPort()); + $this->assertEquals("3306", $dsn->getPort()); $this->assertEquals("database", $dsn->getDatabase()); $this->assertEquals("charset=utf8&timezone=UTC", $dsn->getQuery()); @@ -23,7 +23,7 @@ class DSNTest extends TestCase $this->assertEquals("user", $dsn->getUser()); $this->assertNull($dsn->getPassword()); $this->assertEquals("localhost", $dsn->getHost()); - $this->assertEquals(3306, $dsn->getPort()); + $this->assertEquals("3306", $dsn->getPort()); $this->assertEquals("database", $dsn->getDatabase()); $this->assertEquals("charset=utf8&timezone=UTC", $dsn->getQuery()); From 1632ae61eb6bc306ed9fbc8343fb3b3b8cb92269 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 17 Oct 2022 19:43:51 +0300 Subject: [PATCH 25/36] Fixing CLI tasks --- app/cli.php | 72 ++++++++++++++++++++++++++++++++++ app/init.php | 2 +- app/tasks/maintenance.php | 55 -------------------------- app/tasks/usage.php | 44 ++------------------- src/Appwrite/Resque/Worker.php | 4 +- 5 files changed, 78 insertions(+), 99 deletions(-) diff --git a/app/cli.php b/app/cli.php index 6447de592b..618ba56d1c 100644 --- a/app/cli.php +++ b/app/cli.php @@ -6,7 +6,79 @@ require_once __DIR__ . '/controllers/general.php'; use Utopia\App; use Utopia\CLI\CLI; use Utopia\CLI\Console; +use Utopia\Cache\Adapter\Sharding; +use Utopia\Cache\Cache; +use Utopia\Config\Config; +use Utopia\Database\Database; use Utopia\Database\Validator\Authorization; +use InfluxDB\Database as InfluxDatabase; + +function getInfluxDB(): InfluxDatabase +{ + global $register; + + $client = $register->get('influxdb'); /** @var InfluxDB\Client $client */ + $attempts = 0; + $max = 10; + $sleep = 1; + + do { // check if telegraf database is ready + try { + $attempts++; + $database = $client->selectDB('telegraf'); + if (in_array('telegraf', $client->listDatabases())) { + break; // leave the do-while if successful + } + } catch (\Throwable $th) { + Console::warning("InfluxDB not ready. Retrying connection ({$attempts})..."); + if ($attempts >= $max) { + throw new \Exception('InfluxDB database not ready yet'); + } + sleep($sleep); + } + } while ($attempts < $max); + return $database; +} + +function getConsoleDB(): Database +{ + global $register; + + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + + $dbAdapter = $pools + ->get('console') + ->pop() + ->getResource() + ; + + $database = new Database($dbAdapter, getCache()); + + $database->setNamespace('console'); + $database->setDefaultDatabase('appwrite'); + + return $database; +} + +function getCache(): Cache +{ + global $register; + + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + + $list = Config::getParam('pools-cache', []); + $adapters = []; + + foreach ($list as $value) { + $adapters[] = $pools + ->get($value) + ->pop() + ->getResource() + ; + } + + return new Cache(new Sharding($adapters)); +} Authorization::disable(); diff --git a/app/init.php b/app/init.php index 9c813d8b98..e731859b54 100644 --- a/app/init.php +++ b/app/init.php @@ -606,7 +606,7 @@ $register->set('pools', function () { case 'redis': $resource = function() use ($dsnHost, $dsnPort, $dsnPass) { $redis = new Redis(); - @$redis->pconnect($dsnHost, $dsnPort); + @$redis->pconnect($dsnHost, (int)$dsnPort); if($dsnPass) { $redis->auth($dsnPass); } diff --git a/app/tasks/maintenance.php b/app/tasks/maintenance.php index d7a4de77a6..1c16ca6911 100644 --- a/app/tasks/maintenance.php +++ b/app/tasks/maintenance.php @@ -3,15 +3,10 @@ global $cli; use Appwrite\Auth\Auth; -use Appwrite\Database\Pools; use Appwrite\Event\Certificate; use Appwrite\Event\Delete; use Utopia\App; -use Utopia\Cache\Adapter\Sharding; -use Utopia\Cache\Cache; use Utopia\CLI\Console; -use Utopia\Config\Config; -use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\DateTime; use Utopia\Database\Query; @@ -20,8 +15,6 @@ $cli ->task('maintenance') ->desc('Schedules maintenance tasks and publishes them to resque') ->action(function () { - global $register; - Console::title('Maintenance V1'); Console::success(APP_NAME . ' maintenance process v1 has started'); @@ -110,54 +103,6 @@ $cli ->trigger(); } - /** - * Get console database - * @return Database - */ - function getConsoleDB(): Database - { - global $register; - - $pools = $register->get('pools'); /* @var \Utopia\Pools\Group $pools */ - - $dbAdapter = $pools - ->get('console') - ->pop() - ->getResource() - ; - - $database = new Database($dbAdapter, getCache()); - - $database->setNamespace('console'); - $database->setDefaultDatabase('appwrite'); - - return $database; - } - - /** - * Get Cache - * @return Cache - */ - function getCache(): Cache - { - global $register; - - $pools = $register->get('pools'); /* @var \Utopia\Pools\Group $pools */ - - $list = Config::getParam('pools-cache', []); - $adapters = []; - - foreach ($list as $value) { - $adapters[] = $pools - ->get($value) - ->pop() - ->getResource() - ; - } - - return new Cache(new Sharding($adapters)); - } - // # of days in seconds (1 day = 86400s) $interval = (int) App::getEnv('_APP_MAINTENANCE_INTERVAL', '86400'); $executionLogsRetention = (int) App::getEnv('_APP_MAINTENANCE_RETENTION_EXECUTION', '1209600'); diff --git a/app/tasks/usage.php b/app/tasks/usage.php index fc171aa524..d1aeab2e84 100644 --- a/app/tasks/usage.php +++ b/app/tasks/usage.php @@ -2,7 +2,6 @@ global $cli, $register; -use Appwrite\Database\Pools; use Appwrite\Usage\Calculators\Aggregator; use Appwrite\Usage\Calculators\Database; use Appwrite\Usage\Calculators\TimeSeries; @@ -11,39 +10,12 @@ use Utopia\App; use Utopia\CLI\Console; use Utopia\Database\Database as UtopiaDatabase; use Utopia\Database\Validator\Authorization; -use Utopia\Registry\Registry; use Utopia\Logger\Log; use Utopia\Validator\WhiteList; Authorization::disable(); Authorization::setDefaultStatus(false); -function getInfluxDB(Registry &$register): InfluxDatabase -{ - /** @var InfluxDB\Client $client */ - $client = $register->get('influxdb'); - $attempts = 0; - $max = 10; - $sleep = 1; - - do { // check if telegraf database is ready - try { - $attempts++; - $database = $client->selectDB('telegraf'); - if (in_array('telegraf', $client->listDatabases())) { - break; // leave the do-while if successful - } - } catch (\Throwable $th) { - Console::warning("InfluxDB not ready. Retrying connection ({$attempts})..."); - if ($attempts >= $max) { - throw new \Exception('InfluxDB database not ready yet'); - } - sleep($sleep); - } - } while ($attempts < $max); - return $database; -} - $logError = function (Throwable $error, string $action = 'syncUsageStats') use ($register) { $logger = $register->get('logger'); @@ -78,7 +50,6 @@ $logError = function (Throwable $error, string $action = 'syncUsageStats') use ( Console::warning($error->getTraceAsString()); }; - function aggregateTimeseries(UtopiaDatabase $database, InfluxDatabase $influxDB, callable $logError): void { $interval = (int) App::getEnv('_APP_USAGE_TIMESERIES_INTERVAL', '30'); // 30 seconds (by default) @@ -120,21 +91,12 @@ $cli ->task('usage') ->param('type', 'timeseries', new WhiteList(['timeseries', 'database'])) ->desc('Schedules syncing data from influxdb to Appwrite console db') - ->action(function (string $type) use ($register, $logError) { + ->action(function (string $type) use ($logError) { Console::title('Usage Aggregation V1'); Console::success(APP_NAME . ' usage aggregation process v1 has started'); - $redis = $register->get('cache'); - $dbPool = $register->get('dbPool'); - - $database = $dbPool->getConsoleDB(); - $pdo = $dbPool->getPDO($database); - $database = Pools::wait( - Pools::getDatabase($pdo, $redis, '_console'), - 'projects', - ); - - $influxDB = getInfluxDB($register); + $database = getConsoleDB(); + $influxDB = getInfluxDB(); switch ($type) { case 'timeseries': diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index 28e7106b7e..e504cae679 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -201,7 +201,7 @@ abstract class Worker { global $register; - $pools = $register->get('pools'); /* @var \Utopia\Pools\Group $pools */ + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ $dbAdapter = $pools ->get('console') @@ -225,7 +225,7 @@ abstract class Worker { global $register; - $pools = $register->get('pools'); /* @var \Utopia\Pools\Group $pools */ + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ $list = Config::getParam('pools-cache', []); $adapters = []; From 52d44f0599e3960da0dea04e64d4df0f79edcb30 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 17 Oct 2022 20:26:21 +0300 Subject: [PATCH 26/36] Updated Realtime server --- app/realtime.php | 167 +++++++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 79 deletions(-) diff --git a/app/realtime.php b/app/realtime.php index cea2f89b68..d0e4ea760b 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -1,7 +1,6 @@ get('pools'); /** @var \Utopia\Pools\Group $pools */ + + $dbAdapter = $pools + ->get('console') + ->pop() + ->getResource() + ; + + $database = new Database($dbAdapter, getCache()); + + $database->setNamespace('console'); + $database->setDefaultDatabase('appwrite'); + + return $database; +} + +function getProjectDB(Document $project): Database +{ + global $register; + + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + + if($project->isEmpty() || $project->getId() === 'console') { + return getConsoleDB(); + } + + $dbAdapter = $pools + ->get($project->getAttribute('database')) + ->pop() + ->getResource() + ; + + $database = new Database($dbAdapter, getCache()); + $database->setNamespace('_'.$project->getInternalId()); + $database->setDefaultDatabase('appwrite'); + + return $database; +} + +function getCache(): Cache +{ + global $register; + + $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ + + $list = Config::getParam('pools-cache', []); + $adapters = []; + + foreach ($list as $value) { + $adapters[] = $pools + ->get($value) + ->pop() + ->getResource() + ; + } + + return new Cache(new Sharding($adapters)); +} + $realtime = new Realtime(); /** @@ -92,38 +158,6 @@ $logError = function (Throwable $error, string $action) use ($register) { $server->error($logError); -function getDatabase(Registry &$register, string $projectId) -{ - $redis = $register->get('redisPool')->get(); - $dbPool = $register->get('dbPool'); - - /** Get the console DB */ - $database = $dbPool->getConsoleDB(); - $pdo = $dbPool->getPDOFromPool($database); - $database = Pools::wait( - Pools::getDatabase($pdo->getConnection(), $redis, '_console'), - 'realtime' - ); - - if ($projectId !== 'console') { - $project = Authorization::skip(fn() => $database->getDocument('projects', $projectId)); - $database = $project->getAttribute('database', ''); - $pdo = $dbPool->getPDOFromPool($database); - $database = Pools::wait( - Pools::getDatabase($pdo->getConnection(), $redis, "_{$project->getInternalId()}"), - 'realtime' - ); - } - - return [ - $database, - function () use ($register, $redis) { - $register->get('dbPool')->reset(); - $register->get('redisPool')->put($redis); - } - ]; -} - $server->onStart(function () use ($stats, $register, $containerId, &$statsDocument, $logError) { sleep(5); // wait for the initial database schema to be ready Console::success('Server started successfully'); @@ -133,7 +167,8 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume */ go(function () use ($register, $containerId, &$statsDocument) { $attempts = 0; - [$database, $returnDatabase] = getDatabase($register, 'console'); + $database = getConsoleDB(); + do { try { $attempts++; @@ -153,7 +188,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume sleep(DATABASE_RECONNECT_SLEEP); } } while (true); - call_user_func($returnDatabase); + $register->get('pools')->reclaim(); }); /** @@ -169,7 +204,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume } try { - [$database, $returnDatabase] = getDatabase($register, 'console'); + $database = getConsoleDB(); $statsDocument ->setAttribute('timestamp', DateTime::now()) @@ -179,7 +214,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume } catch (\Throwable $th) { call_user_func($logError, $th, "updateWorkerDocument"); } finally { - call_user_func($returnDatabase); + $register->get('pools')->reclaim(); } }); }); @@ -195,7 +230,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, * Sending current connections to project channels on the console project every 5 seconds. */ if ($realtime->hasSubscriber('console', Role::users()->toString(), 'project')) { - [$database, $returnDatabase] = getDatabase($register, '_console'); + $database = getConsoleDB(); $payload = []; @@ -240,7 +275,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, ])); } - call_user_func($returnDatabase); + $register->get('pools')->reclaim(); } /** * Sending test message for SDK E2E tests every 5 seconds. @@ -275,8 +310,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, } $start = time(); - /** @var Redis $redis */ - $redis = $register->get('redisPool')->get(); + $redis = $register->get('pools')->get('pubsub')->pop()->getResource(); /** @var Redis $redis */ $redis->setOption(Redis::OPT_READ_TIMEOUT, -1); if ($redis->ping(true)) { @@ -295,18 +329,17 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, if ($realtime->hasSubscriber($projectId, 'user:' . $userId)) { $connection = array_key_first(reset($realtime->subscriptions[$projectId]['user:' . $userId])); - [$consoleDatabase, $returnConsoleDatabase] = getDatabase($register, 'console'); + $consoleDatabase = getConsoleDB(); $project = Authorization::skip(fn() => $consoleDatabase->getDocument('projects', $projectId)); - [$database, $returnDatabase] = getDatabase($register, $project->getId()); + $database = getProjectDB($project); $user = $database->getDocument('users', $userId); $roles = Auth::getRoles($user); $realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']); - - call_user_func($returnDatabase); - call_user_func($returnConsoleDatabase); + + $register->get('pools')->reclaim(); } } @@ -334,7 +367,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, call_user_func($logError, $th, "pubSubConnection"); Console::error('Pub/sub error: ' . $th->getMessage()); - $register->get('redisPool')->put($redis); + $register->get('pools')->reclaim(); $attempts++; sleep(DATABASE_RECONNECT_SLEEP); continue; @@ -349,15 +382,8 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, $request = new Request($request); $response = new Response(new SwooleResponse()); - /** @var PDO $db */ - $dbPool = $register->get('dbPool'); - /** @var Redis $redis */ - $redis = $register->get('redisPool')->get(); - Console::info("Connection open (user: {$connection})"); - App::setResource('dbPool', fn() => $dbPool); - App::setResource('cache', fn() => $redis); App::setResource('request', fn() => $request); App::setResource('response', fn() => $response); @@ -372,13 +398,9 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, throw new Exception('Missing or unknown project ID', 1008); } - $dbForProject = $app->getResource('dbForProject'); - - /** @var \Utopia\Database\Document $console */ - $console = $app->getResource('console'); - - /** @var \Utopia\Database\Document $user */ - $user = $app->getResource('user'); + $dbForProject = getProjectDB($project); + $console = $app->getResource('console'); /** @var \Utopia\Database\Document $console */ + $user = $app->getResource('user'); /** @var \Utopia\Database\Document $user */ /* * Abuse Check @@ -457,31 +479,19 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, Console::error('[Error] Message: ' . $response['data']['message']); } } finally { - /** - * Put used PDO and Redis Connections back into their pools. - */ - $dbPool->reset(); - $register->get('redisPool')->put($redis); + $register->get('pools')->reclaim(); } }); $server->onMessage(function (int $connection, string $message) use ($server, $register, $realtime, $containerId) { try { $response = new Response(new SwooleResponse()); - $redis = $register->get('redisPool')->get(); - $dbPool = $register->get('dbPool'); $projectId = $realtime->connections[$connection]['projectId']; - - /** Get the console DB */ - $database = $dbPool->getConsoleDB(); - $pdo = $dbPool->getPDOFromPool($database); - $database = Pools::getDatabase($pdo->getConnection(), $redis, '_console'); + $database = getConsoleDB(); if ($projectId !== 'console') { $project = Authorization::skip(fn() => $database->getDocument('projects', $projectId)); - $database = $project->getAttribute('database', ''); - $pdo = $dbPool->getPDOFromPool($database); - $database = Pools::getDatabase($pdo->getConnection(), $redis, "_{$project->getInternalId()}"); + $database = getProjectDB($project); } /* @@ -565,8 +575,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re $server->close($connection, $th->getCode()); } } finally { - $dbPool->reset(); - $register->get('redisPool')->put($redis); + $register->get('pools')->reclaim(); } }); From d5fafe0ffc8ef4ad7d1b918a0a510f63c0cd9101 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Mon, 17 Oct 2022 20:37:28 +0300 Subject: [PATCH 27/36] Fixed realtime tests --- app/realtime.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/realtime.php b/app/realtime.php index d0e4ea760b..39e1c72046 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -384,6 +384,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server, Console::info("Connection open (user: {$connection})"); + App::setResource('pools', fn() => $register->get('pools')); App::setResource('request', fn() => $request); App::setResource('response', fn() => $response); From d5330b4ad41463933a4d09ac61312207732e37e2 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Tue, 18 Oct 2022 14:50:14 +0300 Subject: [PATCH 28/36] Fixed DSN --- src/Appwrite/DSN/DSN.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Appwrite/DSN/DSN.php b/src/Appwrite/DSN/DSN.php index 03f4759387..5605640989 100644 --- a/src/Appwrite/DSN/DSN.php +++ b/src/Appwrite/DSN/DSN.php @@ -25,7 +25,7 @@ class DSN protected string $host; /** - * @var ?int + * @var ?string */ protected ?string $port; From 9fd2cf35eb5a484212c3e5bed17a59ee674d5fe0 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Tue, 18 Oct 2022 14:53:29 +0300 Subject: [PATCH 29/36] Enabled commented test --- tests/e2e/Services/Account/AccountBase.php | 220 ++++++++++----------- 1 file changed, 110 insertions(+), 110 deletions(-) diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index 71205dc6a0..e8bf146316 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -317,137 +317,137 @@ trait AccountBase return $data; } - // /** - // * @depends testCreateAccountSession - // */ - // public function testGetAccountLogs($data): array - // { - // sleep(10); - // $session = $data['session'] ?? ''; - // $sessionId = $data['sessionId'] ?? ''; - // $userId = $data['id'] ?? ''; - // /** - // * Test for SUCCESS - // */ - // $response = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ - // 'origin' => 'http://localhost', - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - // ])); + /** + * @depends testCreateAccountSession + */ + public function testGetAccountLogs($data): array + { + sleep(10); + $session = $data['session'] ?? ''; + $sessionId = $data['sessionId'] ?? ''; + $userId = $data['id'] ?? ''; + /** + * Test for SUCCESS + */ + $response = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ])); - // $this->assertEquals($response['headers']['status-code'], 200); - // $this->assertIsArray($response['body']['logs']); - // $this->assertNotEmpty($response['body']['logs']); - // $this->assertCount(3, $response['body']['logs']); - // $this->assertIsNumeric($response['body']['total']); - // $this->assertContains($response['body']['logs'][1]['event'], ["session.create"]); - // $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); - // $this->assertEquals(true, DateTime::isValid($response['body']['logs'][1]['time'])); + $this->assertEquals($response['headers']['status-code'], 200); + $this->assertIsArray($response['body']['logs']); + $this->assertNotEmpty($response['body']['logs']); + $this->assertCount(3, $response['body']['logs']); + $this->assertIsNumeric($response['body']['total']); + $this->assertContains($response['body']['logs'][1]['event'], ["session.create"]); + $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); + $this->assertEquals(true, DateTime::isValid($response['body']['logs'][1]['time'])); - // $this->assertEquals('Windows', $response['body']['logs'][1]['osName']); - // $this->assertEquals('WIN', $response['body']['logs'][1]['osCode']); - // $this->assertEquals('10', $response['body']['logs'][1]['osVersion']); + $this->assertEquals('Windows', $response['body']['logs'][1]['osName']); + $this->assertEquals('WIN', $response['body']['logs'][1]['osCode']); + $this->assertEquals('10', $response['body']['logs'][1]['osVersion']); - // $this->assertEquals('browser', $response['body']['logs'][1]['clientType']); - // $this->assertEquals('Chrome', $response['body']['logs'][1]['clientName']); - // $this->assertEquals('CH', $response['body']['logs'][1]['clientCode']); - // $this->assertEquals('70.0', $response['body']['logs'][1]['clientVersion']); - // $this->assertEquals('Blink', $response['body']['logs'][1]['clientEngine']); + $this->assertEquals('browser', $response['body']['logs'][1]['clientType']); + $this->assertEquals('Chrome', $response['body']['logs'][1]['clientName']); + $this->assertEquals('CH', $response['body']['logs'][1]['clientCode']); + $this->assertEquals('70.0', $response['body']['logs'][1]['clientVersion']); + $this->assertEquals('Blink', $response['body']['logs'][1]['clientEngine']); - // $this->assertEquals('desktop', $response['body']['logs'][1]['deviceName']); - // $this->assertEquals('', $response['body']['logs'][1]['deviceBrand']); - // $this->assertEquals('', $response['body']['logs'][1]['deviceModel']); - // $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); + $this->assertEquals('desktop', $response['body']['logs'][1]['deviceName']); + $this->assertEquals('', $response['body']['logs'][1]['deviceBrand']); + $this->assertEquals('', $response['body']['logs'][1]['deviceModel']); + $this->assertEquals($response['body']['logs'][1]['ip'], filter_var($response['body']['logs'][1]['ip'], FILTER_VALIDATE_IP)); - // $this->assertEquals('--', $response['body']['logs'][1]['countryCode']); - // $this->assertEquals('Unknown', $response['body']['logs'][1]['countryName']); + $this->assertEquals('--', $response['body']['logs'][1]['countryCode']); + $this->assertEquals('Unknown', $response['body']['logs'][1]['countryName']); - // $this->assertContains($response['body']['logs'][2]['event'], ["user.create"]); - // $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); - // $this->assertEquals(true, DateTime::isValid($response['body']['logs'][2]['time'])); + $this->assertContains($response['body']['logs'][2]['event'], ["user.create"]); + $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); + $this->assertEquals(true, DateTime::isValid($response['body']['logs'][2]['time'])); - // $this->assertEquals('Windows', $response['body']['logs'][2]['osName']); - // $this->assertEquals('WIN', $response['body']['logs'][2]['osCode']); - // $this->assertEquals('10', $response['body']['logs'][2]['osVersion']); + $this->assertEquals('Windows', $response['body']['logs'][2]['osName']); + $this->assertEquals('WIN', $response['body']['logs'][2]['osCode']); + $this->assertEquals('10', $response['body']['logs'][2]['osVersion']); - // $this->assertEquals('browser', $response['body']['logs'][2]['clientType']); - // $this->assertEquals('Chrome', $response['body']['logs'][2]['clientName']); - // $this->assertEquals('CH', $response['body']['logs'][2]['clientCode']); - // $this->assertEquals('70.0', $response['body']['logs'][2]['clientVersion']); - // $this->assertEquals('Blink', $response['body']['logs'][2]['clientEngine']); + $this->assertEquals('browser', $response['body']['logs'][2]['clientType']); + $this->assertEquals('Chrome', $response['body']['logs'][2]['clientName']); + $this->assertEquals('CH', $response['body']['logs'][2]['clientCode']); + $this->assertEquals('70.0', $response['body']['logs'][2]['clientVersion']); + $this->assertEquals('Blink', $response['body']['logs'][2]['clientEngine']); - // $this->assertEquals('desktop', $response['body']['logs'][2]['deviceName']); - // $this->assertEquals('', $response['body']['logs'][2]['deviceBrand']); - // $this->assertEquals('', $response['body']['logs'][2]['deviceModel']); - // $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); + $this->assertEquals('desktop', $response['body']['logs'][2]['deviceName']); + $this->assertEquals('', $response['body']['logs'][2]['deviceBrand']); + $this->assertEquals('', $response['body']['logs'][2]['deviceModel']); + $this->assertEquals($response['body']['logs'][2]['ip'], filter_var($response['body']['logs'][2]['ip'], FILTER_VALIDATE_IP)); - // $this->assertEquals('--', $response['body']['logs'][2]['countryCode']); - // $this->assertEquals('Unknown', $response['body']['logs'][2]['countryName']); + $this->assertEquals('--', $response['body']['logs'][2]['countryCode']); + $this->assertEquals('Unknown', $response['body']['logs'][2]['countryName']); - // $responseLimit = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ - // 'origin' => 'http://localhost', - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - // ]), [ - // 'queries' => [ 'limit(1)' ], - // ]); + $responseLimit = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]), [ + 'queries' => [ 'limit(1)' ], + ]); - // $this->assertEquals($responseLimit['headers']['status-code'], 200); - // $this->assertIsArray($responseLimit['body']['logs']); - // $this->assertNotEmpty($responseLimit['body']['logs']); - // $this->assertCount(1, $responseLimit['body']['logs']); - // $this->assertIsNumeric($responseLimit['body']['total']); + $this->assertEquals($responseLimit['headers']['status-code'], 200); + $this->assertIsArray($responseLimit['body']['logs']); + $this->assertNotEmpty($responseLimit['body']['logs']); + $this->assertCount(1, $responseLimit['body']['logs']); + $this->assertIsNumeric($responseLimit['body']['total']); - // $this->assertEquals($response['body']['logs'][0], $responseLimit['body']['logs'][0]); + $this->assertEquals($response['body']['logs'][0], $responseLimit['body']['logs'][0]); - // $responseOffset = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ - // 'origin' => 'http://localhost', - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - // ]), [ - // 'queries' => [ 'offset(1)' ], - // ]); + $responseOffset = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]), [ + 'queries' => [ 'offset(1)' ], + ]); - // $this->assertEquals($responseOffset['headers']['status-code'], 200); - // $this->assertIsArray($responseOffset['body']['logs']); - // $this->assertNotEmpty($responseOffset['body']['logs']); - // $this->assertCount(2, $responseOffset['body']['logs']); - // $this->assertIsNumeric($responseOffset['body']['total']); + $this->assertEquals($responseOffset['headers']['status-code'], 200); + $this->assertIsArray($responseOffset['body']['logs']); + $this->assertNotEmpty($responseOffset['body']['logs']); + $this->assertCount(2, $responseOffset['body']['logs']); + $this->assertIsNumeric($responseOffset['body']['total']); - // $this->assertEquals($response['body']['logs'][1], $responseOffset['body']['logs'][0]); + $this->assertEquals($response['body']['logs'][1], $responseOffset['body']['logs'][0]); - // $responseLimitOffset = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ - // 'origin' => 'http://localhost', - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, - // ]), [ - // 'queries' => [ 'limit(1)', 'offset(1)' ], - // ]); + $responseLimitOffset = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'cookie' => 'a_session_' . $this->getProject()['$id'] . '=' . $session, + ]), [ + 'queries' => [ 'limit(1)', 'offset(1)' ], + ]); - // $this->assertEquals($responseLimitOffset['headers']['status-code'], 200); - // $this->assertIsArray($responseLimitOffset['body']['logs']); - // $this->assertNotEmpty($responseLimitOffset['body']['logs']); - // $this->assertCount(1, $responseLimitOffset['body']['logs']); - // $this->assertIsNumeric($responseLimitOffset['body']['total']); + $this->assertEquals($responseLimitOffset['headers']['status-code'], 200); + $this->assertIsArray($responseLimitOffset['body']['logs']); + $this->assertNotEmpty($responseLimitOffset['body']['logs']); + $this->assertCount(1, $responseLimitOffset['body']['logs']); + $this->assertIsNumeric($responseLimitOffset['body']['total']); - // $this->assertEquals($response['body']['logs'][1], $responseLimitOffset['body']['logs'][0]); - // /** - // * Test for FAILURE - // */ - // $response = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ - // 'origin' => 'http://localhost', - // 'content-type' => 'application/json', - // 'x-appwrite-project' => $this->getProject()['$id'], - // ])); + $this->assertEquals($response['body']['logs'][1], $responseLimitOffset['body']['logs'][0]); + /** + * Test for FAILURE + */ + $response = $this->client->call(Client::METHOD_GET, '/account/logs', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ])); - // $this->assertEquals($response['headers']['status-code'], 401); + $this->assertEquals($response['headers']['status-code'], 401); - // return $data; - // } + return $data; + } // TODO Add tests for OAuth2 session creation From d51c37951431a99b25a36f649e8779b0007a9e43 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Wed, 19 Oct 2022 11:35:30 +0300 Subject: [PATCH 30/36] Fixed linter errors --- app/cli.php | 8 +++---- app/controllers/api/health.php | 40 ++++++++++++++++---------------- app/controllers/api/projects.php | 2 +- app/init.php | 40 ++++++++++++++++---------------- app/realtime.php | 14 +++++------ app/tasks/doctor.php | 34 +++++++++++++-------------- src/Appwrite/Resque/Worker.php | 23 +++++++++--------- 7 files changed, 80 insertions(+), 81 deletions(-) diff --git a/app/cli.php b/app/cli.php index 618ba56d1c..be39f0e9ef 100644 --- a/app/cli.php +++ b/app/cli.php @@ -45,7 +45,7 @@ function getConsoleDB(): Database global $register; $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - + $dbAdapter = $pools ->get('console') ->pop() @@ -65,10 +65,10 @@ function getCache(): Cache global $register; $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - + $list = Config::getParam('pools-cache', []); $adapters = []; - + foreach ($list as $value) { $adapters[] = $pools ->get($value) @@ -103,7 +103,7 @@ $cli $cli ->error(function ($error) { - if(App::getEnv('_APP_ENV', 'development')) { + if (App::getEnv('_APP_ENV', 'development')) { Console::error($error); } else { Console::error($error->getMessage()); diff --git a/app/controllers/api/health.php b/app/controllers/api/health.php index 1fdbf0fc1d..f65e65ba23 100644 --- a/app/controllers/api/health.php +++ b/app/controllers/api/health.php @@ -76,23 +76,23 @@ App::get('/v1/health/db') $adapter = $pools->get($database)->pop()->getResource(); $checkStart = \microtime(true); - - if($adapter->ping()) { + + if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'pass', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } else { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); @@ -133,23 +133,23 @@ App::get('/v1/health/cache') $adapter = $pools->get($database)->pop()->getResource(); $checkStart = \microtime(true); - - if($adapter->ping()) { + + if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'pass', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } else { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); @@ -190,23 +190,23 @@ App::get('/v1/health/queue') $adapter = $pools->get($database)->pop()->getResource(); $checkStart = \microtime(true); - - if($adapter->ping()) { + + if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'pass', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } else { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); @@ -247,23 +247,23 @@ App::get('/v1/health/pubsub') $adapter = $pools->get($database)->pop()->getResource(); $checkStart = \microtime(true); - - if($adapter->ping()) { + + if ($adapter->ping()) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'pass', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } else { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); } } catch (\Throwable $th) { $output[] = new Document([ - 'name' => $key." ($database)", + 'name' => $key . " ($database)", 'status' => 'fail', 'ping' => \round((\microtime(true) - $checkStart) / 1000) ]); diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 3262a52164..230355f104 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -75,7 +75,7 @@ App::post('/v1/projects') ->inject('pools') ->action(function (string $projectId, string $name, string $teamId, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Cache $cache, Group $pools) { - + $team = $dbForConsole->getDocument('teams', $teamId); if ($team->isEmpty()) { diff --git a/app/init.php b/app/init.php index e731859b54..560c30ab3b 100644 --- a/app/init.php +++ b/app/init.php @@ -499,7 +499,7 @@ $register->set('logger', function () { }); $register->set('pools', function () { - $group= new Group(); + $group = new Group(); $fallbackForDB = URLURL::unparse([ 'scheme' => 'mariadb', @@ -556,14 +556,14 @@ $register->set('pools', function () { $schemes = $connection['schemes'] ?? []; $config = []; $dsns = explode(',', $connection['dsns'] ?? ''); - + foreach ($dsns as &$dsn) { $dsn = explode('=', $dsn); - $name = ($multipe) ? $key.'_'.$dsn[0] : $key; + $name = ($multipe) ? $key . '_' . $dsn[0] : $key; $dsn = $dsn[1] ?? ''; $config[] = $name; - if(empty($dsn)) { + if (empty($dsn)) { //throw new Exception(Exception::GENERAL_SERVER_ERROR, "Missing value for DSN connection in {$key}"); continue; } @@ -575,15 +575,15 @@ $register->set('pools', function () { $dsnPass = $dsn->getPassword(); $dsnScheme = $dsn->getDatabase(); - if(!in_array($dsn->getScheme(), $schemes)) { + if (!in_array($dsn->getScheme(), $schemes)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid console database scheme"); } /** * Get Resource - * + * * Creation could be reused accross connection types like database, cache, queue, etc. - * + * * Resource assignment to an adapter will happen below. */ @@ -591,7 +591,7 @@ $register->set('pools', function () { case 'mysql': case 'mariadb': $resource = function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnScheme) { - return new PDOProxy(function() use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnScheme) { + return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnScheme) { return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnScheme};charset=utf8mb4", $dsnUser, $dsnPass, array( PDO::ATTR_TIMEOUT => 3, // Seconds PDO::ATTR_PERSISTENT => true, @@ -604,18 +604,18 @@ $register->set('pools', function () { }; break; case 'redis': - $resource = function() use ($dsnHost, $dsnPort, $dsnPass) { + $resource = function () use ($dsnHost, $dsnPort, $dsnPass) { $redis = new Redis(); @$redis->pconnect($dsnHost, (int)$dsnPort); - if($dsnPass) { + if ($dsnPass) { $redis->auth($dsnPass); } $redis->setOption(Redis::OPT_READ_TIMEOUT, -1); - + return $redis; }; break; - + default: throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid scheme"); break; @@ -632,7 +632,7 @@ $register->set('pools', function () { 'mysql' => new MySQL($resource()), default => null }; - + break; case 'queue': $adapter = $resource(); @@ -646,25 +646,25 @@ $register->set('pools', function () { default => null }; break; - + default: throw new Exception(Exception::GENERAL_SERVER_ERROR, "Server error: Missing adapter implementation."); break; } - + return $adapter; }); $group->add($pool); } - Config::setParam('pools-'.$key, $config); + Config::setParam('pools-' . $key, $config); } try { $group->fill(); } catch (\Throwable $th) { - Console::error('Connection failure: '.$th->getMessage()); + Console::error('Connection failure: ' . $th->getMessage()); } return $group; @@ -1022,7 +1022,7 @@ App::setResource('console', function () { }, []); App::setResource('dbForProject', function (Group $pools, Database $dbForConsole, Cache $cache, Document $project) { - if($project->isEmpty() || $project->getId() === 'console') { + if ($project->isEmpty() || $project->getId() === 'console') { return $dbForConsole; } @@ -1033,7 +1033,7 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForConsole, ; $database = new Database($dbAdapter, $cache); - $database->setNamespace('_'.$project->getInternalId()); + $database->setNamespace('_' . $project->getInternalId()); $database->setDefaultDatabase('appwrite'); return $database; @@ -1057,7 +1057,7 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) { App::setResource('cache', function (Group $pools) { $list = Config::getParam('pools-cache', []); $adapters = []; - + foreach ($list as $value) { $adapters[] = $pools ->get($value) diff --git a/app/realtime.php b/app/realtime.php index 39e1c72046..35c20c7c9a 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -38,7 +38,7 @@ function getConsoleDB(): Database global $register; $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - + $dbAdapter = $pools ->get('console') ->pop() @@ -59,7 +59,7 @@ function getProjectDB(Document $project): Database $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - if($project->isEmpty() || $project->getId() === 'console') { + if ($project->isEmpty() || $project->getId() === 'console') { return getConsoleDB(); } @@ -70,7 +70,7 @@ function getProjectDB(Document $project): Database ; $database = new Database($dbAdapter, getCache()); - $database->setNamespace('_'.$project->getInternalId()); + $database->setNamespace('_' . $project->getInternalId()); $database->setDefaultDatabase('appwrite'); return $database; @@ -81,10 +81,10 @@ function getCache(): Cache global $register; $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - + $list = Config::getParam('pools-cache', []); $adapters = []; - + foreach ($list as $value) { $adapters[] = $pools ->get($value) @@ -168,7 +168,7 @@ $server->onStart(function () use ($stats, $register, $containerId, &$statsDocume go(function () use ($register, $containerId, &$statsDocument) { $attempts = 0; $database = getConsoleDB(); - + do { try { $attempts++; @@ -338,7 +338,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $roles = Auth::getRoles($user); $realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']); - + $register->get('pools')->reclaim(); } } diff --git a/app/tasks/doctor.php b/app/tasks/doctor.php index b1a47fdb26..daeaaa3f52 100644 --- a/app/tasks/doctor.php +++ b/app/tasks/doctor.php @@ -107,13 +107,13 @@ $cli try { $adapter = $pools->get($database)->pop()->getResource(); - if($adapter->ping()) { - Console::success('🟢 '.str_pad("{$key}({$database})", 50, '.').'connected'); + if ($adapter->ping()) { + Console::success('🟢 ' . str_pad("{$key}({$database})", 50, '.') . 'connected'); } else { - Console::error('🔴 '.str_pad("{$key}({$database})", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("{$key}({$database})", 47, '.') . 'disconnected'); } } catch (\Throwable $th) { - Console::error('🔴 '.str_pad("{$key}.({$database})", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("{$key}.({$database})", 47, '.') . 'disconnected'); } } } @@ -130,13 +130,13 @@ $cli try { $adapter = $pools->get($pool)->pop()->getResource(); - if($adapter->ping()) { - Console::success('🟢 '.str_pad("{$key}({$pool})", 50, '.').'connected'); + if ($adapter->ping()) { + Console::success('🟢 ' . str_pad("{$key}({$pool})", 50, '.') . 'connected'); } else { - Console::error('🔴 '.str_pad("{$key}({$pool})", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("{$key}({$pool})", 47, '.') . 'disconnected'); } } catch (\Throwable $th) { - Console::error('🔴 '.str_pad("{$key}({$pool})", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("{$key}({$pool})", 47, '.') . 'disconnected'); } } } @@ -149,12 +149,12 @@ $cli ); if ((@$antivirus->ping())) { - Console::success('🟢 '.str_pad("Antivirus", 50, '.').'connected'); + Console::success('🟢 ' . str_pad("Antivirus", 50, '.') . 'connected'); } else { - Console::error('🔴 '.str_pad("Antivirus", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("Antivirus", 47, '.') . 'disconnected'); } } catch (\Throwable $th) { - Console::error('🔴 '.str_pad("Antivirus", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("Antivirus", 47, '.') . 'disconnected'); } } @@ -167,29 +167,29 @@ $cli $mail->AltBody = 'Hello World'; $mail->send(); - Console::success('🟢 '.str_pad("SMTP", 50, '.').'connected'); + Console::success('🟢 ' . str_pad("SMTP", 50, '.') . 'connected'); } catch (\Throwable $th) { - Console::error('🔴 '.str_pad("SMTP", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("SMTP", 47, '.') . 'disconnected'); } $host = App::getEnv('_APP_STATSD_HOST', 'telegraf'); $port = App::getEnv('_APP_STATSD_PORT', 8125); if ($fp = @\fsockopen('udp://' . $host, $port, $errCode, $errStr, 2)) { - Console::success('🟢 '.str_pad("StatsD", 50, '.').'connected'); + Console::success('🟢 ' . str_pad("StatsD", 50, '.') . 'connected'); \fclose($fp); } else { - Console::error('🔴 '.str_pad("StatsD", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("StatsD", 47, '.') . 'disconnected'); } $host = App::getEnv('_APP_INFLUXDB_HOST', ''); $port = App::getEnv('_APP_INFLUXDB_PORT', ''); if ($fp = @\fsockopen($host, $port, $errCode, $errStr, 2)) { - Console::success('🟢 '.str_pad("InfluxDB", 50, '.').'connected'); + Console::success('🟢 ' . str_pad("InfluxDB", 50, '.') . 'connected'); \fclose($fp); } else { - Console::error('🔴 '.str_pad("InfluxDB", 47, '.').'disconnected'); + Console::error('🔴 ' . str_pad("InfluxDB", 47, '.') . 'disconnected'); } \sleep(0.2); diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index 618b5817de..e1a3dc2fad 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -141,9 +141,8 @@ abstract class Worker try { $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ $pools->reclaim(); - - $this->shutdown(); + $this->shutdown(); } catch (\Throwable $error) { foreach (self::$errorCallbacks as $errorCallback) { $errorCallback($error, "shutdown", $this->getName()); @@ -176,20 +175,20 @@ abstract class Worker $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - if($project->isEmpty() || $project->getId() === 'console') { + if ($project->isEmpty() || $project->getId() === 'console') { return $this->getConsoleDB(); } - + $dbAdapter = $pools ->get($project->getAttribute('database')) ->pop() ->getResource() ; - + $database = new Database($dbAdapter, $this->getCache()); - $database->setNamespace('_'.$project->getInternalId()); + $database->setNamespace('_' . $project->getInternalId()); $database->setDefaultDatabase('appwrite'); - + return $database; } @@ -202,7 +201,7 @@ abstract class Worker global $register; $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - + $dbAdapter = $pools ->get('console') ->pop() @@ -217,7 +216,7 @@ abstract class Worker return $database; } - + /** * Get Cache * @return Cache @@ -227,10 +226,10 @@ abstract class Worker global $register; $pools = $register->get('pools'); /** @var \Utopia\Pools\Group $pools */ - + $list = Config::getParam('pools-cache', []); $adapters = []; - + foreach ($list as $value) { $adapters[] = $pools ->get($value) @@ -238,7 +237,7 @@ abstract class Worker ->getResource() ; } - + return new Cache(new Sharding($adapters)); } From 159fd5fc597a8317812b7f020ca2b457e5394d39 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Wed, 19 Oct 2022 15:41:38 +0300 Subject: [PATCH 31/36] Change URLURL to AppwriteURL --- app/init.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/init.php b/app/init.php index 560c30ab3b..e808a92f3d 100644 --- a/app/init.php +++ b/app/init.php @@ -37,7 +37,7 @@ use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\IP; use Appwrite\Network\Validator\URL; use Appwrite\OpenSSL\OpenSSL; -use Appwrite\URL\URL as URLURL; +use Appwrite\URL\URL as AppwriteURL; use Appwrite\Usage\Stats; use Appwrite\Utopia\View; use Utopia\App; @@ -501,14 +501,14 @@ $register->set('pools', function () { $group = new Group(); - $fallbackForDB = URLURL::unparse([ + $fallbackForDB = AppwriteURL::unparse([ 'scheme' => 'mariadb', 'host' => App::getEnv('_APP_DB_HOST', 'mariadb'), 'port' => App::getEnv('_APP_DB_PORT', '3306'), 'user' => App::getEnv('_APP_DB_USER', ''), 'pass' => App::getEnv('_APP_DB_PASS', ''), ]); - $fallbackForRedis = URLURL::unparse([ + $fallbackForRedis = AppwriteURL::unparse([ 'scheme' => 'redis', 'host' => App::getEnv('_APP_REDIS_HOST', 'redis'), 'port' => App::getEnv('_APP_REDIS_PORT', '6379'), From a1157fb49bdf149dd363ed9472fdc9596b7c7886 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Wed, 19 Oct 2022 15:59:13 +0300 Subject: [PATCH 32/36] Env vars clean ups --- app/views/install/compose.phtml | 119 +++++++++++++++++--------------- docker-compose.yml | 85 +++++++++++++++++++---- 2 files changed, 136 insertions(+), 68 deletions(-) diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index 164e370d93..1d7fdcd046 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -88,15 +88,15 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_TARGET + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - - _APP_CONNECTIONS_PUBSUB - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE @@ -184,12 +184,15 @@ services: - _APP_WORKER_PER_CORE - _APP_OPTIONS_ABUSE - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_PUBSUB + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_USAGE_STATS - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -208,14 +211,15 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -238,7 +242,6 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -262,14 +265,15 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_STORAGE_DEVICE - _APP_STORAGE_S3_ACCESS_KEY - _APP_STORAGE_S3_SECRET @@ -310,14 +314,15 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -337,14 +342,15 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -368,14 +374,15 @@ services: - _APP_DOMAIN - _APP_DOMAIN_TARGET - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -394,14 +401,15 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_CONNECTIONS_QUEUE - _APP_FUNCTIONS_TIMEOUT - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST @@ -486,7 +494,6 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_QUEUE - _APP_SMTP_HOST - _APP_SMTP_PORT - _APP_SMTP_SECURE @@ -510,7 +517,6 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_QUEUE - _APP_SMS_PROVIDER - _APP_SMS_FROM - _APP_LOGGING_PROVIDER @@ -531,13 +537,15 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_TARGET + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - _APP_MAINTENANCE_INTERVAL - _APP_MAINTENANCE_RETENTION_EXECUTION - _APP_MAINTENANCE_RETENTION_CACHE @@ -560,17 +568,19 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_INFLUXDB_HOST - - _APP_INFLUXDB_PORT - - _APP_USAGE_TIMESERIES_INTERVAL - - _APP_USAGE_DATABASE_INTERVAL + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT + - _APP_USAGE_TIMESERIES_INTERVAL + - _APP_USAGE_DATABASE_INTERVAL - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -590,17 +600,19 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_INFLUXDB_HOST - - _APP_INFLUXDB_PORT - - _APP_USAGE_TIMESERIES_INTERVAL - - _APP_USAGE_DATABASE_INTERVAL + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT + - _APP_USAGE_TIMESERIES_INTERVAL + - _APP_USAGE_DATABASE_INTERVAL - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -620,7 +632,6 @@ services: - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS - - _APP_CONNECTIONS_QUEUE mariadb: image: mariadb:10.7 # fix issues when upgrading using: mysql_upgrade -u root -p diff --git a/docker-compose.yml b/docker-compose.yml index be0711fee0..ea70cf331a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -133,6 +133,11 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_TARGET + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -214,8 +219,15 @@ services: - _APP_WORKER_PER_CORE - _APP_OPTIONS_ABUSE - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS - _APP_CONNECTIONS_DB_CONSOLE - _APP_CONNECTIONS_DB_PROJECT - _APP_CONNECTIONS_CACHE @@ -240,6 +252,11 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -298,6 +315,11 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -329,6 +351,11 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -358,6 +385,11 @@ services: - _APP_OPENSSL_KEY_V1 - _APP_EXECUTOR_SECRET - _APP_EXECUTOR_HOST + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -390,6 +422,11 @@ services: - _APP_DOMAIN - _APP_DOMAIN_TARGET - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -418,6 +455,11 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -548,6 +590,11 @@ services: - _APP_DOMAIN - _APP_DOMAIN_TARGET - _APP_OPENSSL_KEY_V1 + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -580,17 +627,22 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_INFLUXDB_HOST - - _APP_INFLUXDB_PORT - - _APP_USAGE_TIMESERIES_INTERVAL - - _APP_USAGE_DATABASE_INTERVAL + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_USAGE_TIMESERIES_INTERVAL + - _APP_USAGE_DATABASE_INTERVAL - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG @@ -613,17 +665,22 @@ services: environment: - _APP_ENV - _APP_OPENSSL_KEY_V1 - - _APP_CONNECTIONS_DB_CONSOLE - - _APP_CONNECTIONS_DB_PROJECT - - _APP_CONNECTIONS_CACHE - - _APP_INFLUXDB_HOST - - _APP_INFLUXDB_PORT - - _APP_USAGE_TIMESERIES_INTERVAL - - _APP_USAGE_DATABASE_INTERVAL + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER - _APP_REDIS_PASS + - _APP_INFLUXDB_HOST + - _APP_INFLUXDB_PORT + - _APP_CONNECTIONS_DB_CONSOLE + - _APP_CONNECTIONS_DB_PROJECT + - _APP_CONNECTIONS_CACHE + - _APP_USAGE_TIMESERIES_INTERVAL + - _APP_USAGE_DATABASE_INTERVAL - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG From e5c62c6730f1e09df22f00e710417adfaf5c2118 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Wed, 19 Oct 2022 16:55:58 +0300 Subject: [PATCH 33/36] Fixed usage of DSN database --- app/cli.php | 1 - app/controllers/api/projects.php | 1 - app/init.php | 15 +++++++-------- app/realtime.php | 2 -- src/Appwrite/Resque/Worker.php | 2 -- 5 files changed, 7 insertions(+), 14 deletions(-) diff --git a/app/cli.php b/app/cli.php index be39f0e9ef..3a62c80816 100644 --- a/app/cli.php +++ b/app/cli.php @@ -55,7 +55,6 @@ function getConsoleDB(): Database $database = new Database($dbAdapter, getCache()); $database->setNamespace('console'); - $database->setDefaultDatabase('appwrite'); return $database; } diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 230355f104..74b9cc298e 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -131,7 +131,6 @@ App::post('/v1/projects') $dbForProject = new Database($pools->get($database)->pop()->getResource(), $cache); $dbForProject->setNamespace("_{$project->getInternalId()}"); - $dbForProject->setDefaultDatabase('appwrite'); $dbForProject->create(App::getEnv('_APP_DB_SCHEMA', 'appwrite')); diff --git a/app/init.php b/app/init.php index e808a92f3d..6d72bedf43 100644 --- a/app/init.php +++ b/app/init.php @@ -573,9 +573,10 @@ $register->set('pools', function () { $dsnPort = $dsn->getPort(); $dsnUser = $dsn->getUser(); $dsnPass = $dsn->getPassword(); - $dsnScheme = $dsn->getDatabase(); + $dsnScheme = $dsn->getScheme(); + $dsnDatabase = $dsn->getDatabase(); - if (!in_array($dsn->getScheme(), $schemes)) { + if (!in_array($dsnScheme, $schemes)) { throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid console database scheme"); } @@ -587,12 +588,12 @@ $register->set('pools', function () { * Resource assignment to an adapter will happen below. */ - switch ($dsn->getScheme()) { + switch ($dsnScheme) { case 'mysql': case 'mariadb': - $resource = function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnScheme) { - return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnScheme) { - return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnScheme};charset=utf8mb4", $dsnUser, $dsnPass, array( + $resource = function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { + return new PDOProxy(function () use ($dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) { + return new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array( PDO::ATTR_TIMEOUT => 3, // Seconds PDO::ATTR_PERSISTENT => true, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, @@ -1034,7 +1035,6 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForConsole, $database = new Database($dbAdapter, $cache); $database->setNamespace('_' . $project->getInternalId()); - $database->setDefaultDatabase('appwrite'); return $database; }, ['pools', 'dbForConsole', 'cache', 'project']); @@ -1049,7 +1049,6 @@ App::setResource('dbForConsole', function (Group $pools, Cache $cache) { $database = new Database($dbAdapter, $cache); $database->setNamespace('console'); - $database->setDefaultDatabase('appwrite'); return $database; }, ['pools', 'cache']); diff --git a/app/realtime.php b/app/realtime.php index 35c20c7c9a..8cd28c193f 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -48,7 +48,6 @@ function getConsoleDB(): Database $database = new Database($dbAdapter, getCache()); $database->setNamespace('console'); - $database->setDefaultDatabase('appwrite'); return $database; } @@ -71,7 +70,6 @@ function getProjectDB(Document $project): Database $database = new Database($dbAdapter, getCache()); $database->setNamespace('_' . $project->getInternalId()); - $database->setDefaultDatabase('appwrite'); return $database; } diff --git a/src/Appwrite/Resque/Worker.php b/src/Appwrite/Resque/Worker.php index e1a3dc2fad..5d05d77576 100644 --- a/src/Appwrite/Resque/Worker.php +++ b/src/Appwrite/Resque/Worker.php @@ -187,7 +187,6 @@ abstract class Worker $database = new Database($dbAdapter, $this->getCache()); $database->setNamespace('_' . $project->getInternalId()); - $database->setDefaultDatabase('appwrite'); return $database; } @@ -211,7 +210,6 @@ abstract class Worker $database = new Database($dbAdapter, $this->getCache()); $database->setNamespace('console'); - $database->setDefaultDatabase('appwrite'); return $database; } From e113253e35eb788ed0e1e1d69dda38e23731688b Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Wed, 19 Oct 2022 17:13:38 +0300 Subject: [PATCH 34/36] Fixed tests --- app/init.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/init.php b/app/init.php index 6d72bedf43..a08dcfd137 100644 --- a/app/init.php +++ b/app/init.php @@ -634,6 +634,8 @@ $register->set('pools', function () { default => null }; + $adapter->setDefaultDatabase($dsn->getDatabase()); + break; case 'queue': $adapter = $resource(); From 54469e9b4d3d1c4835cb558cab77f74ec85565e5 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Fri, 21 Oct 2022 08:41:12 +0300 Subject: [PATCH 35/36] Unused classes --- app/controllers/api/teams.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index a42b9d317e..9f1aedf483 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -20,7 +20,6 @@ use Appwrite\Utopia\Response; use MaxMind\Db\Reader; use Utopia\App; use Utopia\Audit\Audit; -use Utopia\CLI\Console; use Utopia\Config\Config; use Utopia\Database\Database; use Utopia\Database\Document; @@ -36,9 +35,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Locale\Locale; use Utopia\Validator\Text; -use Utopia\Validator\Range; use Utopia\Validator\ArrayList; -use Utopia\Validator\WhiteList; App::post('/v1/teams') ->desc('Create Team') From 27c4e24fa553d98999cbc82f312734f7a2892c91 Mon Sep 17 00:00:00 2001 From: Eldad Fux Date: Fri, 21 Oct 2022 08:41:17 +0300 Subject: [PATCH 36/36] Unused classes --- app/controllers/api/functions.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index d3a26b414e..f2745281fc 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -25,7 +25,6 @@ use Appwrite\Task\Validator\Cron; use Appwrite\Utopia\Database\Validator\Queries\Deployments; use Appwrite\Utopia\Database\Validator\Queries\Executions; use Appwrite\Utopia\Database\Validator\Queries\Functions; -use Appwrite\Utopia\Database\Validator\Queries\Variables; use Utopia\App; use Utopia\Database\Database; use Utopia\Database\Document; @@ -33,7 +32,6 @@ use Utopia\Database\DateTime; use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Validator\ArrayList; -use Utopia\Validator\Assoc; use Utopia\Validator\Text; use Utopia\Validator\Range; use Utopia\Validator\WhiteList;