RFC: 5.next - Add Lock component for distributed locking#19370
Draft
dereuromark wants to merge 7 commits intocakephp:5.nextfrom
Draft
RFC: 5.next - Add Lock component for distributed locking#19370dereuromark wants to merge 7 commits intocakephp:5.nextfrom
dereuromark wants to merge 7 commits intocakephp:5.nextfrom
Conversation
Introduces a new Lock component that provides distributed locking
mechanisms to prevent race conditions when multiple processes access
shared resources.
Features:
- LockInterface defines the contract for lock engines
- LockInstance value object represents an acquired lock
- Lock static facade for convenient access (similar to Cache)
- LockRegistry for managing engine instances
- Four lock engines:
- RedisLockEngine: Uses Redis SET NX with Lua scripts for atomicity
- MemcachedLockEngine: Uses Memcached add() for atomic acquisition
- FileLockEngine: Uses flock() for local filesystem locking
- NullLockEngine: No-op engine for testing and development
Key capabilities:
- Non-blocking acquire() and blocking acquireBlocking()
- Lock refresh to extend TTL
- Owner verification on release (prevents releasing others' locks)
- Force release for administrative purposes
- synchronized() helper for automatic lock/unlock around callbacks
Example usage:
Lock::setConfig('default', ['className' => RedisLockEngine::class]);
$lock = Lock::acquire('my-resource');
if ($lock !== null) {
try {
// Critical section
} finally {
Lock::release($lock);
}
}
// Or using synchronized helper:
$result = Lock::synchronized('my-resource', function () {
return doWork();
});
- Use empty array comparison instead of count() in MemcachedLockEngine - Combine nested if statements in RedisLockEngine
Use getConfig() instead of direct array access to properly handle defaults when config is not fully initialized.
Import the env() function from Cake\Core to fix "undefined function" errors.
Use getVersion() to verify the Memcached connection actually works, allowing tests to be properly skipped when connection fails.
Wrap cleanupTestLocks in try-catch to prevent test failures when Redis connection drops during cleanup.
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.
Summary
Introduces a new Lock component that provides distributed locking mechanisms to prevent race conditions when multiple processes access shared resources.
This was identified as a gap in CakePHP compared to other frameworks (Symfony Lock component, Laravel Cache::lock()). The implementation follows CakePHP's existing patterns from the Cache component.
Features
Lock Engines
Key Capabilities
acquire()and blockingacquireBlocking()with timeoutsynchronized()helper for automatic lock/unlock around callbacksExample Usage
Namespace: Lock
Namespaces WITHOUT split packages (monolith-only):
This seems to fit, since we dont need its own package usually here.
Related Discussion
This addresses the gap identified when comparing CakePHP to other frameworks. See: Symfony Lock component, Laravel's atomic locks.
We could also make this a plugin. But it seems this could be a core feature.
PS: Symfony added 2 years after Lock also Semaphore functionality. I descoped that for now, could also be something added within the next 2 years if thats what people need/want.