Skip to content

feat: accept RedisCluster in Distributed lock#1

Closed
premtsd-code wants to merge 1 commit intoutopia-php:mainfrom
premtsd-code:feat-redis-cluster-support
Closed

feat: accept RedisCluster in Distributed lock#1
premtsd-code wants to merge 1 commit intoutopia-php:mainfrom
premtsd-code:feat-redis-cluster-support

Conversation

@premtsd-code
Copy link
Copy Markdown

Summary

Widens the type accepted by Distributed::__construct from \Redis to \Redis | \RedisCluster so the lock primitive can be used against clustered Redis/Dragonfly deployments.

Why

Utopia\Lock\Distributed uses three single-key operations:

  • set($key, $token, ['NX', 'EX' => $ttl]) — acquire (line 88)
  • get($key)isHeld() check (line 139)
  • eval($script, [$key, $token], 1) — atomic compare-and-delete release / TTL refresh (line 149)

All three are slot-deterministic single-key ops that the PHP \RedisCluster client routes transparently via CRC16-based slot routing. Both client classes implement these methods with effectively identical signatures for single-key operations, so no algorithmic change is required — the lock's correctness, TTL semantics, and compare-and-delete release behaviour all hold unchanged on cluster mode.

What does NOT change

  • Lock acquire/release atomicity (single-key SET NX EX, single-key Lua DEL)
  • TTL self-heal on master failure
  • Token-based fencing (compare-and-delete)
  • Per-key failover semantics — same as single-instance Redis: each lock lives on one master (the slot owner), so master failure mid-lock has the same exposure as standalone mode. The Redlock multi-master quorum guarantee is orthogonal to this change and remains out of scope (it would require multiple independent Redis instances, not just cluster mode).

What's not addressed here

  • Multi-key locks would need hash tags ({group}:keyA, {group}:keyB) to force same-slot placement. This PR makes no change there because the lock primitive is single-key by design.

Test plan

  • composer analyze (PHPStan) passes
  • composer lint (Pint) passes
  • Existing DistributedTest unit tests pass against \Redis (no behavioural change for the standalone path)
  • Manual: instantiate against \RedisCluster connected to a 3-master Dragonfly/Redis cluster and verify acquire / release / refresh / isHeld / withLock all behave correctly. (Adding an automated cluster test requires CI infrastructure changes beyond this PR's scope; happy to follow up.)

Downstream

This unblocks Appwrite\Locking\Lock in appwrite/appwrite#12062 — the appwrite-side resource can then return \Redis | \RedisCluster from _APP_CONNECTIONS_CACHE based on the DSN scheme (redis:// vs redis-cluster://), matching how the cache pool already works.

The lock primitive uses only single-key operations (SET NX EX, GET, and
single-key Lua EVAL via runScript), all of which behave identically on
\Redis and \RedisCluster — the cluster client routes by hash slot
transparently. Widening the type lets clustered Dragonfly/Redis
deployments use the same Distributed lock without an external client
wrapper.

No algorithmic changes; same TTL, same compare-and-delete release
script, same correctness properties per key. Multi-master quorum
guarantees (Redlock) remain out of scope — single-key locks on cluster
mode have the same per-key failover semantics as single-instance Redis.
premtsd-code added a commit to appwrite/appwrite that referenced this pull request Apr 29, 2026
Cloud production runs four separate single-master+replica Dragonfly
deployments (cache, queue-dragonfly, queue-usage, pubsub-dragonfly),
not sharded Redis Cluster topology — confirmed by deploy/cloud/values
+ environments/production/*.values.yaml (Dragonfly Operator with
replicas=2 = 1 primary + 1 read replica), and by the dev DSN scheme
'redis://' (not 'redis-cluster://').

So a standard \Redis client suffices for the direct redis resource
(timelimit, Lock). Cloud just needs to pass _APP_REDIS_HOST/PORT/USER/
PASS through to the appwrite container — handled in the cloud PR's
docker-compose.yml change.

This reverts the resource to its original pre-PR shape. The
utopia-php/lock cluster-support PR (utopia-php/lock#1) stays open at
upstream as a future-ready option if cloud ever moves to actual
Redis Cluster mode.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant