eonx-com / easy-lock
Framework agnostic locking features
Requires
- php: ^8.4
- psr/log: ^3.0
- symfony/config: ^7.4 || ^8.0
- symfony/dependency-injection: ^7.4 || ^8.0
- symfony/http-kernel: ^7.4 || ^8.0
- symfony/lock: ^7.4 || ^8.0
- symfony/messenger: ^7.4 || ^8.0
- symfony/service-contracts: ^3.5
Requires (Dev)
- doctrine/collections: ^1.7.2 || ^2.6
- doctrine/dbal: ^3.8 || ^4.4
- doctrine/doctrine-bundle: ^2.12 || ^3.2
- doctrine/orm: ^2.20 || ^3.6
- laravel/framework: ^13.0
- phpunit/phpunit: ^12.5|^13.0
Suggests
- eonx-com/easy-async: For EasyAsync integration
- eonx-com/easy-logging: For Laravel and EasyLogging integration
- symfony/messenger: For Symfony Messenger integration
Provides
None
Conflicts
None
Replaces
None
- 7.x-dev
- 7.0.0-alpha.2
- 7.0.0-alpha.1
- 6.x-dev
- dev-master / 6.29.x-dev
- 6.28.0
- 6.27.0
- 6.26.1
- 6.26.0
- 6.25.2
- 6.25.1
- 6.25.0
- 6.24.1
- 6.24.0
- 6.23.1
- 6.23.0
- 6.22.5
- 6.22.4
- 6.22.3
- 6.22.2
- 6.22.1
- 6.22.0
- 6.21.0
- 6.20.1
- 6.20.0
- 6.19.4
- 6.19.3
- 6.19.2
- 6.19.1
- 6.19.0
- 6.18.5
- 6.18.4
- 6.18.3
- 6.18.2
- 6.18.1
- 6.18.0
- 6.17.6
- 6.17.5
- 6.17.4
- 6.17.3
- 6.17.2
- 6.17.1
- 6.17.0
- 6.16.0
- 6.15.2
- 6.15.1
- 6.15.0
- 6.14.17
- 6.14.16
- 6.14.15
- 6.14.14
- 6.14.13
- 6.14.12
- 6.14.11
- 6.14.10
- 6.14.9
- 6.14.8
- 6.14.7
- 6.14.6
- 6.14.5
- 6.14.4
- 6.14.3
- 6.14.2
- 6.14.1
- 6.14.0
- 6.13.0
- 6.12.7
- 6.12.6
- 6.12.5
- 6.12.4
- 6.12.3
- 6.12.2
- 6.12.1
- 6.12.0
- 6.11.1
- 6.11.0
- 6.10.0
- 6.9.0
- 6.8.0
- 6.7.0
- 6.6.0
- 6.5.0
- 6.4.5
- 6.4.4
- 6.4.3
- 6.4.2
- 6.4.1
- 6.4.0
- 6.3.2
- 6.3.1
- 6.3.0
- 6.2.0
- 6.1.0
- 6.0.3
- 6.0.2
- 6.0.1
- 6.0.0
- 6.0.0-rc.1
- 6.0.0-alpha.5
- 6.0.0-alpha.4
- 6.0.0-alpha.3
- 6.0.0-alpha.2
- 6.0.0-alpha
- 5.13.2
- 5.13.1
- 5.13.0
- 5.12.1
- 5.12.0
- 5.11.3
- 5.11.2
- 5.11.1
- 5.11.0
- 5.10.5
- 5.10.4
- 5.10.3
- 5.10.2
- 5.10.1
- 5.10.0
- 5.9.3
- 5.9.2
- 5.9.1
- 5.9.0
- 5.8.0
- 5.7.5
- 5.7.4
- 5.7.3
- 5.7.2
- 5.7.1
- 5.7.0
- 5.6.16
- 5.6.15
- 5.6.14
- 5.6.13
- 5.6.12
- 5.6.11
- 5.6.10
- 5.6.9
- 5.6.8
- 5.6.7
- 5.6.6
- 5.6.5
- 5.6.4
- 5.6.3
- 5.6.2
- 5.6.1
- 5.6.0
- 5.5.0
- 5.4.0
- 5.3.2
- 5.3.1
- 5.3.0
- 5.2.2
- 5.2.1
- 5.2.0
- 5.1.7
- 5.1.6
- 5.1.5
- 5.1.4
- 5.1.3
- 5.1.2
- 5.1.1
- 5.1.0
- 5.0.3
- 5.0.2
- 5.0.1
- 5.0.0
- 4.x-dev
- 4.5.8
- 4.5.7
- 4.5.6
- 4.5.5
- 4.5.4
- 4.5.3
- 4.5.1
- 4.5.0
- 4.4.5
- 4.4.4
- 4.4.3
- 4.4.2
- 4.4.1
- 4.4.0
- 4.3.38
- 4.3.37
- 4.3.36
- 4.3.35
- 4.3.34
- 4.3.33
- 4.3.32
- 4.3.31
- 4.3.30
- 4.3.29
- 4.3.28
- 4.3.27
- 4.3.26
- 4.3.25
- 4.3.24
- 4.3.23
- 4.3.22
- 4.3.21
- 4.3.20
- 4.3.19
- 4.3.18
- 4.3.17
- 4.3.16
- 4.3.15
- 4.3.14
- 4.3.13
- 4.3.12
- 4.3.11
- 4.3.10
- 4.3.9
- 4.3.8
- 4.3.7
- 4.3.6
- 4.3.5
- 4.3.4
- 4.3.3
- 4.3.2
- 4.3.1
- 4.3.0
- 4.2.7
- 4.2.6
- 4.2.5
- 4.2.4
- 4.2.3
- 4.2.2
- 4.2.1
- 4.2.0
- 4.1.42
- 4.1.41
- 4.1.40
- 4.1.39
- 4.1.38
- 4.1.37
- 4.1.36
- 4.1.35
- 4.1.34
- 4.1.33
- 4.1.32
- 4.1.31
- 4.1.30
- 4.1.29
- 4.1.28
- 4.1.27
- 4.1.26
- 4.1.25
- 4.1.24
- 4.1.23
- 4.1.22
- 4.1.21
- 4.1.20
- 4.1.19
- 4.1.18
- 4.1.17
- 4.1.16
- 4.1.15
- 4.1.14
- 4.1.13
- 4.1.12
- 4.1.11
- 4.1.10
- 4.1.9
- 4.1.8
- 4.1.7
- 4.1.6
- 4.1.5
- 4.1.4
- 4.1.3
- 4.1.2
- 4.1.1
- 4.1.0
- 4.1.0-rc1
- 4.0.15
- 4.0.14
- 4.0.13
- 4.0.12
- 4.0.11
- 4.0.10
- 4.0.9
- 4.0.8
- 4.0.7
- 4.0.6
- 4.0.5
- 4.0.4
- 4.0.3
- 4.0.2
- 4.0.1
- 3.x-dev
- 3.4.29
- 3.4.28
- 3.4.27
- 3.4.26
- 3.4.25
- 3.4.24
- 3.4.24-beta1
- 3.4.23
- 3.4.22
- 3.4.21
- 3.4.20
- 3.4.19
- 3.4.18
- 3.4.17
- 3.4.16
- 3.4.15
- 3.4.14
- 3.4.13
- 3.4.12
- 3.4.11
- 3.4.10
- 3.4.9
- 3.4.8
- 3.4.7
- 3.4.6
- 3.4.5
- 3.4.4
- 3.4.3
- 3.4.2
- 3.4.1
- 3.4.0
- 3.3.15
- 3.3.14
- 3.3.13
- 3.3.12
- 3.3.11
- 3.3.10
- 3.3.9
- 3.3.8
- 3.3.7
- 3.3.6
- 3.3.5
- 3.3.4
- 3.3.3
- 3.3.2
- 3.3.1
- 3.3.0
- 3.2.14
- 3.2.13
- 3.2.12
- 3.2.11
- 3.2.10
- 3.2.9
- 3.2.8
- 3.2.7
- 3.2.6
- 3.2.5
- 3.2.4
- 3.2.3
- 3.2.2
- 3.2.1
- 3.2.0
- 3.2.0-alpha4
- 3.2.0-alpha3
- 3.2.0-alpha2
- 3.2.0-alpha1
- 3.1.9
- 3.1.8
- 3.1.7
- 3.1.6
- 3.1.5
- 3.1.5-alpha8
- 3.1.5-alpha7
- 3.1.5-alpha6
- 3.1.5-alpha5
- 3.1.5-alpha4
- 3.1.5-alpha3
- 3.1.5-alpha2
- 3.1.5-alpha1
- 3.1.4
- 3.1.3
- 3.1.2
- 3.1.2-alpha4
- 3.1.2-alpha3
- 3.1.2-alpha2
- 3.1.2-alpha1
- 3.1.1
- 3.1.1-alpha2
- 3.1.1-alpha1
- 3.1.0
- 3.1.0-rc2
- 3.1.0-rc1
- 3.0.30
- 3.0.29
- 3.0.28
- 3.0.27
- 3.0.26
- 3.0.25
- 3.0.24
- 3.0.23
- 3.0.22
- 3.0.21
- 3.0.20
- 3.0.19
- 3.0.18
- 3.0.17
- 3.0.16
- 3.0.15
- 3.0.14
- 3.0.14-alpha3
- 3.0.14-alpha2
- 3.0.14-alpha1
- 3.0.13
- 3.0.12
- 3.0.11
- 3.0.10
- 3.0.9
- 3.0.8
- 3.0.7
- 3.0.6
- 3.0.5
- 3.0.5-alpha4
- 3.0.5-alpha3
- 3.0.5-alpha2
- 3.0.5-alpha1
- 3.0.4
- 3.0.3
- 3.0.2
- 3.0.1
- 3.0.0
- 3.0.0-alpha2
- 3.0.0-alpha1
- 2.5.33
- 2.5.32
- 2.5.31
- 2.5.30
- 2.5.29
- 2.5.28
- 2.5.27
- v2.5.26
- v2.5.25
- v2.5.24
- v2.5.23
- v2.5.22
- v2.5.21
- v2.5.20
- v2.5.19
- v2.5.18
- v2.5.17
- v2.5.16
- v2.5.15
- v2.5.14
- v2.5.13
- v2.5.12
- v2.5.11
- v2.5.10
- v2.5.9
- v2.5.8
- v2.5.7
- v2.5.6
- v2.5.5
- v2.5.4
- v2.5.3
- v2.5.2
- v2.5.1
- v2.5.0
- v2.4.49
- v2.4.48
- v2.4.47
- v2.4.46
- v2.4.45
- v2.4.44
- v2.4.43
- v2.4.42
- v2.4.41
- v2.4.40
- v2.4.39
- v2.4.38
- v2.4.37
- v2.4.36
- v2.4.35
- v2.4.34
- v2.4.33
- v2.4.32
- v2.4.31
- v2.4.30
- v2.4.29
- v2.4.28
- v2.4.27
- v2.4.26
- v2.4.25
- v2.4.24
- v2.4.23
- v2.4.22
- v2.4.21
- v2.4.20
- v2.4.19
- dev-feature/swoole-error-response
- dev-hotfix/swoole-pdo-client-pool-own-implementation
- dev-np/investigate-swoole-errors-in-aws
- dev-feature/git-subtree-for-split-1
- dev-feature/git-subtree-for-split
- dev-feature/easy-async-refactor
- dev-3.x-split-test
- dev-feature/exception-to-status-code
- dev-feature/easy-request-id
- dev-feature/easy-bugsnag
- dev-feature/error-handler-framework-agnostic
- dev-integration/easy-api-token-and-easy-security
- dev-feature/easy-webhook-profiler
- dev-feature/refactory-easy-api-token
- dev-feature/search-in-easy-core
- dev-feature/easy-webhooks
This package is auto-updated.
Last update: 2026-11-11 14:44:59 UTC
README
---eonx_docs--- title: Introduction weight: 0 ---eonx_docs---
The purpose of this package isn't to be used within a project by the application as there is no point in creating another level of abstraction in that case BUT only to allow eonx-com packages to dispatch events without having to think about the event dispatcher used by each of our projects.
Require package (Composer)
The recommended way to install this package is to use Composer:
$ composer require eonx-com/easy-lock
Usage
The Symfony Lock component has an excellent documentation and we recommend referring to it.
Connection
To work with this package you simply have to register the connection to use for the locks store as a service under
the easy_lock.connection id. This connection will be given to the StoreFactory, so its value can be anything
supported by the Lock component.
Store
If defining the connection doesn't work for you, you can override the store instance within the service container under
the easy_lock.store id.
Lock factory
The package registers a Symfony\Component\Lock\LockFactory built on its own store and logger under the
easy_lock.lock_factory id, so there is no need to create your own instance of the lock factory. Wire it explicitly
where you need it:
use Symfony\Component\Lock\LockFactory; final readonly class MyService { public function __construct( private LockFactory $lockFactory, ) { } public function doSomething(): void { $lock = $this->lockFactory->createLock('my-resource'); // ... } }
// config/services.php $services->set(MyService::class) ->arg('$lockFactory', service('easy_lock.lock_factory'));
The same lock factory instance is used by EonX\EasyLock\Common\Locker\LockerInterface internally.
Nothing is registered under the Symfony\Component\Lock\LockFactory class name on purpose. FrameworkBundle claims
that name as soon as framework.lock is enabled, which is the default once symfony/lock is installed, and its
default factory uses a flock store that does not lock across application instances. A plain LockFactory
type-hint therefore resolves to whatever the application configured, which is why the wiring above is explicit.
Messenger middleware and busy locks
EonX\EasyLock\Messenger\Middleware\ProcessWithLockMiddleware handles messages consumed by a worker when the
message implements EonX\EasyLock\Common\ValueObject\WithLockDataInterface or the envelope has
EonX\EasyLock\Messenger\Stamp\WithLockDataStamp. The middleware acquires the lock before it calls the handler and
releases the lock after the handler returns.
When another process holds the lock, the result depends on the retry value of the lock data:
retryisfalse(default): the handler is not called and the message is removed from the transport. The worker acknowledges the message as if it was handled. The middleware:- writes a log record to the
lockchannel with the message class, the lock resource, the lock TTL (300seconds when the lock data does not set it), the transport message ID and the transport name - adds
EonX\EasyLock\Messenger\Stamp\LockNotAcquiredStampto the envelope that the bus returns to the worker. Only worker-side code can see this stamp: the code that receives the result of the bus dispatch in the worker (for example a custom SQS handler) and listeners ofWorkerMessageHandledEvent. The code that sent the message to the transport does not get this envelope
- writes a log record to the
retryistrue: the middleware throwsEonX\EasyLock\Common\Exception\ShouldRetryException. The retry strategy of the transport decides if the message is retried. No log record is written by the middleware.
Removing the message is correct only when the process that holds the lock does the same work, for example when the transport delivers the same message two times. If different messages use the same lock resource, the work of the removed message is lost.
The log level is warning by default because many applications ignore records below warning for channels other than
their own. You can change it:
// config/packages/easy_lock.php namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Psr\Log\LogLevel; return static function (ContainerConfigurator $containerConfigurator): void { $containerConfigurator->extension('easy_lock', [ 'messenger' => [ 'middleware' => [ 'lock_not_acquired_log_level' => LogLevel::INFO, ], ], ]); };
Lock TTL
The lock TTL is 300 seconds when the lock data does not set it. If a worker stops before it releases the lock (the
process is killed, the Lambda function times out), the lock stays until the TTL expires. Choose the TTL as follows:
- Make it longer than the longest time the handler can run. If the lock expires while the handler runs, another worker can handle the same message at the same time.
- Make it shorter than the time after which the transport delivers an unacknowledged message again: the visibility
timeout for SQS,
redeliver_timeoutfor the Doctrine transport. If the TTL is longer, the next delivery after a worker failure finds the old lock and the message is removed without being handled.