PHP 8.3+ library which helps to manage execution in concurent situations (async code, parallel, distributed systems).
composer require mimatus/locksmith- Mutual exclusion / exclusive locks / mutex / serialized execution / semaphore with capacity 1 - lot of buzzwords describing ensurance resource/code is accessed/executed only once
- Semaphore / shared lock - limit access to resource N times at the same time
- Deadlock prevention via max lock wait time and cooperative suspension points
- Versioned locks - resource is locked only for higher/equal versions - prevents processing of outdated data/code
- Async/concurrent-friendly - cooperative suspension points to allow other lock acquisition attempts or allow lock TTL checks for long running processes
- TTL-based locks - locks are held only for specified time
- In-memory semaphore implementation for single-process scenarios
- Redis-based semaphore implementation for multi-process/distributed scenarios
- Extendable via
Semaphoreinterface - implement your own semaphore (e.g., Redis-based, database-based, etc.) - Deadlock prevention via max lock wait time and cooperative suspension points
- Basic in-memory & Redis semaphore implementation
- Feedback and API stabilization
- Documentation improvements
- Redlock algorithm for Redis semaphore
- Predis support for Redis semaphore
- AMPHP Redis client support for Redis semaphore
- MySQL/MariaDB/PostgreSQL semaphore implementation
$locksmith = new Locksmith(
semaphore: new InMemorySemaphore(maxConcurrentLocks: 1) // Single lock at a time -> mutex
);
$resource = new Resource(
namespace: 'test-resource', // Namespace/identifier for resource
version: 1, // Optional resource version
ttlNanoseconds: 1_000_000_000, //How long should be resource locked
);
$locked = $locksmith->locked(
$resource,
maxLockWaitNs: 500_000_000, // How long to wait for lock acquisition - error if exceeded
minSuspensionDelayNs: 10_000 // Minimum delay between retries when lock acquisition fails
);
$locked(function (Closure $suspension): void {
// Critical section - code executed under lock
$suspension(); // Optional - cooperative suspension point to allow other lock acquisition attempts or allow lock TTL checks for long running processes
});
// Lock is released after callback execution$redis = new Redis();
$redis->connect('redis');
$semaphore = new RedisSemaphore(
redisClient: $redis,
maxConcurrentLocks: 3, // Max concurrent locks
);
$locksmith = new Locksmith(semaphore: $semaphore);
$resource = new Resource(
namespace: 'test-resource', // Namespace/identifier for resource
version: 1, // Optional resouce version
ttlNanoseconds: 1_000_000_000, //How long should be resource locked
);
$locked = $locksmith->locked(
$resource,
maxLockWaitNs: 500_000_000, // How long to wait for lock acquisition - error if exceeded
minSuspensionDelayNs: 10_000 // Minimum delay between retries when lock acquisition fails
);
$locked(function (Closure $suspension): void {
// Critical section - code executed under lock
$suspension(); // Optional - cooperative suspension point to allow other lock acquisition attempts or allow lock TTL checks for long running processes
});
// Lock is released after callback executionProject follows Conventional Commits for commit messages.
All necessary commands are available via Makefile.
To see all available commands:
make helpThe most important ones:
composer-install: Install PHP dependencies via Composer.
help: Show help for each of the Makefile recipes.
mago-analyze: Run static analysis via mago.
mago-format: Run code formatting via mago.
mago-lint-fix: Run linting with auto-fix via mago.
mago-lint: Run linting via mago.
run-tests: Run unit tests via PHPUnit.MIT — see License.