Skip to content
Open
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@
"coverage": "./vendor/bin/coverage-check ./tmp/clover.xml 90"
},
"require": {
"php": ">=8.1",
"php": ">=8.4",
"ext-pdo": "*",
"ext-mongodb": "*",
"ext-mbstring": "*",
"utopia-php/framework": "0.33.*",
"utopia-php/cache": "0.13.*",
"utopia-php/pools": "0.8.*",
"utopia-php/cache": "1.0.*",
"utopia-php/pools": "1.0.*",
Comment on lines +41 to +42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find usages of utopia-php/cache and utopia-php/pools in the codebase
cd "$(git rev-parse --show-toplevel)" 2>/dev/null || true

echo "=== Searching for Cache class/namespace usage ==="
rg -n 'Utopia\\Cache|use.*Cache' --type php -C2 | head -100

echo ""
echo "=== Searching for Pools class/namespace usage ==="
rg -n 'Utopia\\Pools|use.*Pool' --type php -C2 | head -100

echo ""
echo "=== Checking for direct instantiation/calls ==="
rg -n '(new Cache|Cache::|->cache\(|new Pool|Pool::)' --type php -C1 | head -50

echo ""
echo "=== Current composer.json versions ==="
rg '"utopia-php/(cache|pools)"' composer.json -A1

Repository: utopia-php/database

Length of output: 10616


🌐 Web query:

utopia-php cache 1.0.0 release breaking changes

💡 Result:

As of January 28, 2026, utopia-php/cache 1.0.0 was released on GitHub, and the release notes do not call out any explicit breaking changes—they only mention: “Implement Reconnection for caches” (PR #61). [1]

That said, the main upgrade risk / likely breaking change I can confirm from the 1.0.0 code changes is a dependency constraint bump:

  • utopia-php/pools requirement changed from 0.8.*1.* (in composer.json). This can break installs that are pinned to utopia-php/pools 0.x or have other dependencies that still require 0.x. [2]

Also note: Packagist may lag GitHub—at the time of this check, Packagist still showed 0.13.1 as the latest published version for utopia-php/cache, so composer require utopia-php/cache:^1.0 may not resolve until Packagist updates. [3]

Sources:
[1] (github.com)
[2] (github.com)
[3] (packagist.org)

Citations:


🌐 Web query:

utopia-php pools 1.0.0 release breaking changes

💡 Result:

For utopia-php/pools v1.0.0 (released Jan 16, 2026), the project’s release notes do not list any explicit API “breaking changes”, but there are two practical breaking-impact items to be aware of:

  • PHP minimum version bump: Packagist shows v1.0.0 requires PHP >=8.4 (whereas the prior 0.8.x line required >=8.3). This is a breaking change for anyone running PHP 8.3 or lower. [1]
  • Concurrency-focused refactor: The only functional change called out in the v1.0.0 release notes is “Refactoring pools for concurrent operations” (PR #24). This may affect behavior in concurrent/coroutine usage even if method signatures stayed the same. [2]

Sources:
[1] Packagist package page (shows v1.0.0/v1.0.1 and PHP requirement) (root.packagist.org)
[2] GitHub v1.0.0 release notes (github.com)

Citations:


Resolve breaking changes in major version upgrades before merging.

Both dependencies have confirmed breaking changes in v1.0.0:

  • utopia-php/pools: PHP minimum version bumped from 8.3 to 8.4+ (hard requirement) and refactored for concurrent operations (PR #24), which may affect runtime behavior.
  • utopia-php/cache: Dependency on utopia-php/pools upgraded to v1.0.

The codebase actively uses both packages (Cache in src/Database/Database.php and Pool in src/Database/Adapter/Pool.php). Given that adapter tests are "not yet passing," verify:

  1. PHP 8.4+ is available in test/deployment environment
  2. Pool concurrency behavior is compatible with current usage patterns
  3. All adapter tests pass before merging
🤖 Prompt for AI Agents
In `@composer.json` around lines 41 - 42, composer.json currently pins
"utopia-php/cache" and "utopia-php/pools" to 1.0.* but v1.0.0 contains breaking
changes (PHP 8.4+ requirement and concurrency refactor); update the PR by either
(a) pinning both deps to the last compatible v0.x.y versions or (b) upgrading
application code to be compatible: ensure CI/test matrix uses PHP 8.4+, run and
fix failing adapter tests in src/Database/Database.php (Cache usage) and
src/Database/Adapter/Pool.php (Pool usage) to handle the new concurrent
behavior, and verify all adapter tests pass before merging.

"utopia-php/mongo": "0.11.*"
},
"require-dev": {
Expand Down
49 changes: 25 additions & 24 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion tests/e2e/Adapter/PoolTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Utopia\Database\Exception\Duplicate;
use Utopia\Database\Exception\Limit;
use Utopia\Database\PDO;
use Utopia\Pools\Adapter\Stack;
use Utopia\Pools\Pool as UtopiaPool;

class PoolTest extends Base
Expand Down Expand Up @@ -43,7 +44,7 @@ public function getDatabase(): Database
$redis->flushAll();
$cache = new Cache(new RedisAdapter($redis));

$pool = new UtopiaPool('mysql', 10, function () {
$pool = new UtopiaPool(new Stack(), 'mysql', 10, function () {
$dbHost = 'mysql';
$dbPort = '3307';
$dbUser = 'root';
Expand Down
110 changes: 110 additions & 0 deletions tests/e2e/Adapter/Scopes/GeneralTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Exception;
use Throwable;
use Utopia\Cache\Adapter\Redis as RedisAdapter;
use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Database\Database;
use Utopia\Database\Document;
Expand All @@ -18,6 +20,7 @@
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
use Utopia\Database\Helpers\Role;
use Utopia\Database\Mirror;
use Utopia\Database\Query;

trait GeneralTests
Expand Down Expand Up @@ -697,6 +700,113 @@ public function testCacheFallback(): void
$this->assertCount(1, $database->find('testRedisFallback', [Query::equal('string', ['text📝'])]));
}

public function testCacheReconnect(): void
{
/** @var Database $database */
$database = $this->getDatabase();

if (!$database->getAdapter()->getSupportForCacheSkipOnFailure()) {
$this->expectNotToPerformAssertions();
return;
}

// Wait for Redis to be fully healthy after previous test
$this->waitForRedis();

// Create new cache with reconnection enabled
$redis = new \Redis();
$redis->connect('redis', 6379);
$cache = new Cache((new RedisAdapter($redis))->setMaxRetries(3));

// For Mirror, we need to set cache on both source and destination
if ($database instanceof Mirror) {
$database->getSource()->setCache($cache);

$mirrorRedis = new \Redis();
$mirrorRedis->connect('redis-mirror', 6379);
$mirrorCache = new Cache((new RedisAdapter($mirrorRedis))->setMaxRetries(3));
$database->getDestination()->setCache($mirrorCache);
}

$database->setCache($cache);

$database->getAuthorization()->cleanRoles();
$database->getAuthorization()->addRole(Role::any()->toString());

try {
$database->createCollection('testCacheReconnect', attributes: [
new Document([
'$id' => ID::custom('title'),
'type' => Database::VAR_STRING,
'size' => 255,
'required' => true,
])
], permissions: [
Permission::read(Role::any()),
Permission::create(Role::any()),
Permission::update(Role::any()),
Permission::delete(Role::any())
]);

$database->createDocument('testCacheReconnect', new Document([
'$id' => 'reconnect_doc',
'title' => 'Test Document',
]));

// Cache the document
$doc = $database->getDocument('testCacheReconnect', 'reconnect_doc');
$this->assertEquals('Test Document', $doc->getAttribute('title'));

// Bring down Redis
$stdout = '';
$stderr = '';
Console::execute('docker ps -a --filter "name=utopia-redis" --format "{{.Names}}" | xargs -r docker stop', "", $stdout, $stderr);
sleep(1);

// Bring back Redis
Console::execute('docker ps -a --filter "name=utopia-redis" --format "{{.Names}}" | xargs -r docker start', "", $stdout, $stderr);
$this->waitForRedis();

// Cache should reconnect - read should work
$doc = $database->getDocument('testCacheReconnect', 'reconnect_doc');
$this->assertEquals('Test Document', $doc->getAttribute('title'));

// Update should work after reconnect
$database->updateDocument('testCacheReconnect', 'reconnect_doc', new Document([
'$id' => 'reconnect_doc',
'title' => 'Updated Title',
]));

$doc = $database->getDocument('testCacheReconnect', 'reconnect_doc');
$this->assertEquals('Updated Title', $doc->getAttribute('title'));
} finally {
// Ensure Redis is running
$stdout = '';
$stderr = '';
Console::execute('docker ps -a --filter "name=utopia-redis" --format "{{.Names}}" | xargs -r docker start', "", $stdout, $stderr);
$this->waitForRedis();

// Cleanup collection if it exists
if ($database->exists() && !$database->getCollection('testCacheReconnect')->isEmpty()) {
$database->deleteCollection('testCacheReconnect');
}
}
}

/**
* Wait for Redis to be ready with a readiness probe
*/
private function waitForRedis(int $maxRetries = 10, int $delayMs = 500): void
{
for ($i = 0; $i < $maxRetries; $i++) {
try {
$redis = new \Redis();
$redis->connect('redis', 6379);
$redis->ping();
return;
} catch (\RedisException $e) {
usleep($delayMs * 1000);
}
}
}
}