feat: wire Redis adapter as test backend (compose + registers + ci)

Wires the new Redis database adapter through the Appwrite stack:
- registers.php: add 'redis' to schemes for console/database/logs pools,
  add an explicit redis resource arm honouring the optional db segment,
  and dispatch to Utopia\Database\Adapter\Redis in the database match
- composer.json: switch utopia-php/database constraint to
  dev-feat-redis-adapter to pick up the new adapter (lockfile bump
  follows after the database PR is pushed to origin)
- docker-compose.yml: add a dedicated redis-mirror service with
  noeviction policy and AOF persistence so the database backend stays
  isolated from the cache instance
- ci.yml: add Redis to default and full database matrices and export
  the matching env vars (_APP_DB_HOST=redis-mirror, port 6379)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jake Barnby
2026-04-30 22:37:46 +12:00
co-authored by Claude Opus 4.7
parent fba473c41a
commit 95e5a6e365
5 changed files with 55 additions and 6 deletions
+7 -2
View File
@@ -216,10 +216,10 @@ jobs:
with: with:
script: | script: |
// TEMP: forcing SQLite/shared on this PR until it goes green; revert before merge. // TEMP: forcing SQLite/shared on this PR until it goes green; revert before merge.
const fullMatrixDatabases = ['MariaDB', 'PostgreSQL', 'MongoDB']; const fullMatrixDatabases = ['MariaDB', 'PostgreSQL', 'MongoDB', 'Redis'];
const fullMatrixModes = ['dedicated', 'shared']; const fullMatrixModes = ['dedicated', 'shared'];
const defaultDatabases = ['SQLite']; const defaultDatabases = ['SQLite', 'Redis'];
const defaultModes = ['shared']; const defaultModes = ['shared'];
core.setOutput('databases', JSON.stringify(defaultDatabases)); core.setOutput('databases', JSON.stringify(defaultDatabases));
@@ -496,6 +496,11 @@ jobs:
echo "_APP_DB_HOST=mongodb" >> $GITHUB_ENV echo "_APP_DB_HOST=mongodb" >> $GITHUB_ENV
echo "_APP_DB_PORT=0" >> $GITHUB_ENV echo "_APP_DB_PORT=0" >> $GITHUB_ENV
echo "_APP_DB_SQLITE_PATH=/storage/sqlite/appwrite.db" >> $GITHUB_ENV echo "_APP_DB_SQLITE_PATH=/storage/sqlite/appwrite.db" >> $GITHUB_ENV
elif [ "${{ matrix.database }}" = "Redis" ]; then
echo "COMPOSE_PROFILES=mongodb" >> $GITHUB_ENV
echo "_APP_DB_ADAPTER=redis" >> $GITHUB_ENV
echo "_APP_DB_HOST=redis-mirror" >> $GITHUB_ENV
echo "_APP_DB_PORT=6379" >> $GITHUB_ENV
fi fi
- name: Login to Docker Hub - name: Login to Docker Hub
+4
View File
@@ -1,3 +1,7 @@
# Unreleased
- Add Redis as a supported database adapter for tests (use `_APP_DB_ADAPTER=redis _APP_DB_HOST=redis-mirror`)
# Version 1.9.0 # Version 1.9.0
## What's Changed ## What's Changed
+21 -3
View File
@@ -14,6 +14,7 @@ use Utopia\Database\Adapter\MariaDB;
use Utopia\Database\Adapter\Mongo; use Utopia\Database\Adapter\Mongo;
use Utopia\Database\Adapter\MySQL; use Utopia\Database\Adapter\MySQL;
use Utopia\Database\Adapter\Postgres; use Utopia\Database\Adapter\Postgres;
use Utopia\Database\Adapter\Redis as RedisAdapter;
use Utopia\Database\Adapter\SQL; use Utopia\Database\Adapter\SQL;
use Utopia\Database\Adapter\SQLite; use Utopia\Database\Adapter\SQLite;
use Utopia\Database\PDO; use Utopia\Database\PDO;
@@ -191,13 +192,13 @@ $register->set('pools', function () {
'type' => 'database', 'type' => 'database',
'dsns' => $fallbackForDB, 'dsns' => $fallbackForDB,
'multiple' => false, 'multiple' => false,
'schemes' => ['mariadb', 'mongodb', 'mysql', 'postgresql', 'sqlite'], 'schemes' => ['mariadb', 'mongodb', 'mysql', 'postgresql', 'redis', 'sqlite'],
], ],
'database' => [ 'database' => [
'type' => 'database', 'type' => 'database',
'dsns' => $fallbackForDB, 'dsns' => $fallbackForDB,
'multiple' => true, 'multiple' => true,
'schemes' => ['mongodb', 'mariadb', 'mysql', 'postgresql', 'sqlite'], 'schemes' => ['mariadb', 'mongodb', 'mysql', 'postgresql', 'redis', 'sqlite'],
], ],
'documentsdb' => [ 'documentsdb' => [
'type' => 'database', 'type' => 'database',
@@ -215,7 +216,7 @@ $register->set('pools', function () {
'type' => 'database', 'type' => 'database',
'dsns' => System::getEnv('_APP_CONNECTIONS_DB_LOGS', $fallbackForDB), 'dsns' => System::getEnv('_APP_CONNECTIONS_DB_LOGS', $fallbackForDB),
'multiple' => false, 'multiple' => false,
'schemes' => ['mongodb', 'mariadb', 'mysql', 'postgresql', 'sqlite'], 'schemes' => ['mariadb', 'mongodb', 'mysql', 'postgresql', 'redis', 'sqlite'],
], ],
'publisher' => [ 'publisher' => [
'type' => 'publisher', 'type' => 'publisher',
@@ -351,6 +352,22 @@ $register->set('pools', function () {
return $pdo; return $pdo;
}); });
}, },
// DSN format: redis://[user:pass@]host:port[/db]
// - "db" segment is the logical Redis DB index (0-15) and is
// optional. Query parameters are not supported.
'redis' => function () use ($dsnHost, $dsnPort, $dsnPass, $dsnDatabase) {
$redis = new \Redis();
@$redis->pconnect($dsnHost, (int)$dsnPort);
if ($dsnPass) {
$redis->auth($dsnPass);
}
if ($dsnDatabase !== '' && \is_numeric($dsnDatabase)) {
$redis->select((int)$dsnDatabase);
}
$redis->setOption(\Redis::OPT_READ_TIMEOUT, -1);
return $redis;
},
default => function () use ($dsnHost, $dsnPort, $dsnPass) { default => function () use ($dsnHost, $dsnPort, $dsnPass) {
$redis = new \Redis(); $redis = new \Redis();
@$redis->pconnect($dsnHost, (int)$dsnPort); @$redis->pconnect($dsnHost, (int)$dsnPort);
@@ -374,6 +391,7 @@ $register->set('pools', function () {
'mysql' => new MySQL($resource()), 'mysql' => new MySQL($resource()),
'mongodb' => new Mongo($resource()), 'mongodb' => new Mongo($resource()),
'postgresql' => new Postgres($resource()), 'postgresql' => new Postgres($resource()),
'redis' => new RedisAdapter($resource()),
'sqlite' => (new SQLite($resource()))->setEmulateMySQL(true), 'sqlite' => (new SQLite($resource()))->setEmulateMySQL(true),
default => null default => null
}; };
+1 -1
View File
@@ -61,7 +61,7 @@
"utopia-php/compression": "0.1.*", "utopia-php/compression": "0.1.*",
"utopia-php/config": "1.*", "utopia-php/config": "1.*",
"utopia-php/console": "0.1.*", "utopia-php/console": "0.1.*",
"utopia-php/database": "dev-feat-sqlite-fts as 5.999.0", "utopia-php/database": "dev-feat-redis-adapter as 5.999.0",
"utopia-php/detector": "0.2.*", "utopia-php/detector": "0.2.*",
"utopia-php/domains": "1.*", "utopia-php/domains": "1.*",
"utopia-php/emails": "0.6.*", "utopia-php/emails": "0.6.*",
+22
View File
@@ -1422,6 +1422,27 @@ services:
timeout: 5s timeout: 5s
retries: 12 retries: 12
# Dedicated Redis instance used as the primary database backend when
# _APP_DB_ADAPTER=redis. Kept separate from the cache instance above so
# that tuning (eviction policy, persistence) can be set for durability
# rather than cache semantics. maxmemory-policy=noeviction is mandatory:
# a database that silently evicts keys would lose user data.
redis-mirror:
image: redis:7.4-alpine
container_name: appwrite-redis-mirror
<<: *x-logging
command: redis-server --maxmemory 1gb --maxmemory-policy noeviction --appendonly yes --save ""
ports: []
networks:
- appwrite
volumes:
- appwrite-redis-mirror:/data:rw
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
coredns: # DNS server for testing purposes (Proxy APIs) coredns: # DNS server for testing purposes (Proxy APIs)
image: coredns/coredns:1.12.4 image: coredns/coredns:1.12.4
container_name: appwrite-coredns container_name: appwrite-coredns
@@ -1514,6 +1535,7 @@ volumes:
appwrite-mongodb-keyfile: appwrite-mongodb-keyfile:
appwrite-postgresql: appwrite-postgresql:
appwrite-redis: appwrite-redis:
appwrite-redis-mirror:
appwrite-cache: appwrite-cache:
appwrite-uploads: appwrite-uploads:
appwrite-imports: appwrite-imports: