Repository navigation
fix(cache): report a cache that refuses an invalidation as unavailable - #1047
Conversation
When the cache refused the save that blocks or publishes a collection's document epoch, or the purge that releases a writer or finishes its invalidation, the write failed with a plain RuntimeException. Callers could not tell that refusal from a bug: Appwrite Cloud translates Utopia\Cache\Exception\Unavailable into a retryable 503, but these reached clients as a 500 general_unknown (CLOUD-3R8F, CLOUD-3R8D, CLOUD-3R94, CLOUD-3RB1), most recently while a Dragonfly node was reloading its dataset. Throw Unavailable for those refusals, and for the same steps of the query cache. It extends RuntimeException, so existing handlers and the retries around each step behave as before. An owner that belongs to another writer stays a RuntimeException: that is a broken invariant, not an unavailable cache. Unavailable ships in utopia-php/cache 5.2, so require ^5.2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
Problem
A write whose cache invalidation the cache refused failed with a plain
RuntimeException:Appwrite Cloud translates
Utopia\Cache\Exception\Unavailableinto a retryable 503 (database_unavailable, ordatabase_outcome_unknownonce something committed). These are the same condition under another type, so they reached clients as a500 general_unknown. They are still occurring on the release that already carries #1043's retries: CLOUD-3R8F, CLOUD-3R8D, CLOUD-3R94 and CLOUD-3RB1, most recently during a Dragonfly reload on 2026-10-22 22:30Z.Fix
Throw
Unavailablewhen the cache refuses one of these steps:UnavailableextendsRuntimeException, so existing handlers and thewithRetriesaround each step are unchanged.Invalid … cache ownerstays aRuntimeException, because it is a broken invariant, not an unavailable cache.Unavailableships inutopia-php/cache5.2, so the requirement moves from^4.0 || ^5.0to^5.2. Appwrite replacesutopia-php/cachewith its own package, so this does not constrain it.Tests
UnavailableCachenow throwsUnavailablefor a purge it cannot confirm, like the real 5.2 circuit breaker.CacheUnavailableTest::testAWriteTheCacheCannotInvalidateIsRolledBackasserts the failure isUnavailable. Without the fix, 4 of its 8 cases fail:RuntimeException is not an instance of Unavailable.QueryTest::testInvalidationPropagatesACacheWriteFailureexpectsUnavailable. Fails without the fix.Locally: the unit suite passes (13128 tests), and Pint and both PHPStan configs are clean. The one exception is
SwooleAbsentTest::testEveryClassLoadsWithoutSwoole, which cannot loadredis.sounder-non this host. CI's image has it.🤖 Generated with Claude Code
Summary by CodeRabbit