Add session locking support to RedisCluster - #2836
Open
rveznaver wants to merge 1 commit into
Open
Conversation
Member
|
Thanks. I will try to make time to play around with this. Session cluster locking would be nice. |
Author
|
Welcome! Let me know if you require any changes, but I do believe the general idea should be safe from a distributed locking standpoint (provided no keys get evicted). |
Author
|
Hi @michael-grunder, did you manage to play with this a bit? |
Member
|
Sorry, I've been swamped. I will give it a test though, it's a useful feature for sure. |
rveznaver
force-pushed
the
cluster_session_lock
branch
from
June 22, 2026 21:15
39db5de to
ee7be30
Compare
Author
|
I have rebased this on the latest
|
rveznaver
force-pushed
the
cluster_session_lock
branch
from
July 2, 2026 21:30
ee7be30 to
a0d09af
Compare
Author
|
Updated the pull request description, the code should now be easier to follow :) |
rveznaver
force-pushed
the
cluster_session_lock
branch
2 times, most recently
from
July 24, 2026 16:13
55997f4 to
fb3a3de
Compare
Author
|
Rebased on latest |
Adds PHP session locking support to the RedisCluster session save handler. The implementation collocates the session lock on the same slot as the session itself, ensures session lock acquisition is atomic, and any operations on the session are made on the slot owner (replicas cannot guarantee data freshness). These three guarantees enable the cluster session locks to behave like those already set up for standalone Redis.
rveznaver
force-pushed
the
cluster_session_lock
branch
from
July 26, 2026 11:55
fb3a3de to
daad26a
Compare
Author
|
Rebased on latest |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
July 2026 update: I realised my former pull request description read more like a stream of consciousness novel than technical writing, so this should be a better version.
Description
This pull request adds PHP session locking support to the RedisCluster session save handler.
The implementation collocates the session lock on the same slot as the session itself, ensures session lock acquisition is atomic, and any operations on the session are made on the slot owner (replicas cannot guarantee data freshness). These three guarantees enable the cluster session locks to behave like those already set up for standalone Redis.
The implementation purposely avoids using any general distributed lock mechanism (i.e. Redlock) given that sessions themselves are already sharded (though both the session and its lock may be replicated). It adds a LUA script for lock acquisition, but defaults to the already existing LUA conditional delete (both Valkey and Redis conditional delete commands are supported as opt-in).
Implementation
Most of the code is a mirror copy of the standalone Redis flow, adapted to work on
RedisCluster. The real work lies in a few notable changes that require attention.added the
redis_cluster_sessionstructThe cluster handle is bundled with the lock status, mirroring the
redis_poolstructadded
generate_cluster_lock_keyandselect_cluster_lock_key_formfunctionsThe cluster lock key uses Redis Cluster Hash tags which basically wraps the session key around braces (thus creating a hash tag) and adds a
_LOCKsuffix, like so:The code also autodetects the case in which there is already a tag inside the session key itself, like so:
The latter use case is strongly discouraged in the
README.md, but support is there as one may imagine someone might want to force all sessions to go to a specific slot.The
select_cluster_lock_key_formfunction was adapted from the Redis source codekeyHashSlot(). It is O(n) so impact is negligible.added
LOCK_RW_LUA_STRLua scriptThe Lua script is the basis of the aforementioned atomic operation. It acquires the lock and reads the session data in a single call. The actual ordering of the operations is in reverse to prevent Redis from doing a
SETon the lock if the session dataGETfails (Redis does not rollback all operations within a LUA script).The script will use
GETEXto refresh the session TTL if set, fallback to regularGET. It supports setting the lock with a TTL and without, butcluster_lock_acquire_and_readsets the lock TTL tomax_execution_timeifredis.session.lock_expireis set to 0. To note: the lock TTL is defined in seconds, but written in milliseconds.The reason the cluster lock key uses hash tags is so this script does not trip
CROSSSLOTand fail.operations sent to master slot
Due to possible stale data, the code ensures operations are sent to the master slot by setting:
That being said, any failover should be automatically handled by following Redis
MOVEDerrors (unless the lock was lost in the failover). This should also work on AWS ElastiCache Serverless (though I would personally not set up sessions on such a cluster).support for multiple lock release commands
Depending on the configured options,
cluster_lock_releasemay call:cluster_lock_release_delex(Redis 8.4+)cluster_lock_release_delifeq(Valkey 9.0+)cluster_lock_release_lua(Lua using existing script)table of function equivalence
Most of the locking functions are a mirror of the standalone session handling code. This is on purpose as I copied them over before adapting them to work on the cluster, so if you are used to reading the session handling code, this should be functionally identical.
generate_cluster_lock_keygenerate_lock_keycluster_set_session_lock_keyset_session_lock_keycluster_lock_acquirelock_acquirecluster_write_allowedwrite_allowedcluster_get_del_resultget_del_resultcluster_lock_releaselock_releasecluster_lock_release_delexlock_release_delexcluster_lock_release_delifeqlock_release_delifeqcluster_lock_release_lualock_release_luaNote:
cluster_send_release_cmd,cluster_read_session_data, andcluster_lock_acquire_and_readare all implemented inline in the standalone flow.Tests
All the tests for session locking on the cluster have been uncommented and helpers have been slightly adapted where necessary.
I have also tested this against both Redis and Valkey clusters in multiple Docker environments, but those tests have not been included as I do not see the repo managing any Docker tests.
Backport on 6.3.0
This feature has also been backported on top of 6.3.0, code is in the 6.3.0_cluster_session_lock branch