ixarlie/mutex-bundle

A Symfony bundle for Mutex implementation for PHP

Installs: 22 945

Dependents: 0

Suggesters: 0

Security: 0

Stars: 4

Watchers: 1

Forks: 1

Open Issues: 0

Type:symfony-bundle

v2.1.0 2023-01-04 18:43 UTC

README

GitHub Actions Codacy Badge Packagist

This bundle integrates the symfony/lock capabilities into kernel.controller events.

For previous releases with arvenil/ninja-mutex dependency follow the version 1

Before continuing, please read the following links for more information.

Install

composer require ixarlie/mutex-bundle "^2.1"

Add the bundle in the kernel class:

$bundles = [
    // ...
    IXarlie\MutexBundle\IXarlieMutexBundle::class => ['all' => true],
    // ...
];

Configuration

# Symfony lock configuration
framework:
    lock:
        main: flock
        alt: semaphore 
i_xarlie_mutex:
    # Add the Symfony lock factories services id
    factories:
        - 'lock.default.factory'
        - 'lock.main.factory'
        - 'lock.alt.factory' 

Locking Strategy

This bundle ships 3 different locking strategies:

  • block (BlockLockingStrategy)

    It attempts to acquire the lock. If the lock is already acquired then an exception is thrown. This strategy does not block until the release of the lock.

  • force (ForceLockingStrategy)

    It acquires the lock. Whether the lock is acquired, it forces a release before acquire it.

  • queue (QueueLockingStrategy)

    It attempts to acquire the lock. Whether the lock is acquired, this strategy will wait until the release of the lock. The queue strategy will work depending on the service configuration.

    Read Blocking section in Symfony Docs

You can implement your own LockingStrategy classes. Use the tag ixarlie_mutex.strategy in your services to register them in the LockExecutor service.

services:
    app.mutex_locking_strategy:
        class: App\Mutex\LockingStrategy
        tags:
            - { name: ixarlie_mutex.strategy }

Naming Strategy

The name option is not required in the annotation. However, a name is mandatory in order to create a LockInterface instance.

This bundle ships 2 naming strategies:

  • DefaultNamingStrategy, if a name is not set in the annotation, this class will use the request information.
  • UserIsolationNamingStrategy, if the userIsolation is enabled, this class will append the token user information to the name value. It decorates DefaultNamingStrategy.

You can implement your own NamingStrategy.

  1. Decorating ixarlie_mutex.naming_strategy (recommended)
services:
    app.mutex_naming_strategy:
        class: App\Mutex\NamingStrategy
        decorates: 'ixarlie_mutex.naming_strategy'
        arguments: ['app.mutex_naming_strategy.inner']
  1. Replacing the alias definition ixarlie_mutex.naming_strategy with your own service id. This will execute only your logic.
services:
    app.mutex_naming_strategy:
        class: App\Mutex\NamingStrategy

    ixarlie_mutex.naming_strategy:
        alias: app.mutex_naming_strategy

Annotation

The MutexRequest annotation can be used only on controller methods.

Options

  • service (required)

The lock factory service name. It should be one of the services listed in the factories setting.

Examples:

framework:
    lock: semaphore

i_xarlie_mutex:
    factories:
        - 'lock.default.factory'
#[MutexRequest(service: 'lock.default.factory')]
framework:
    lock:
        main_lock: flock
        secondary_lock: semaphore

i_xarlie_mutex:
    factories:
        - 'lock.main_lock.factory'
#[MutexRequest(service: 'lock.main_lock.factory')]
  • strategy (required)

One of the registered locking strategies. Read the Locking Strategy section.

Examples:

#[MutexRequest(service: 'lock.default.factory', strategy: 'block')]
#[MutexRequest(service: 'lock.default.factory', strategy: 'queue')]
#[MutexRequest(service: 'lock.default.factory', strategy: 'force')]
  • name (optional)

The lock's name. If no name is provided, the name will be generated using the registered naming strategies.

Note: Read userIsolation option to know how it affects to the name.

Note: The prefix ixarlie_mutex_ is prefixed to the name.

Note: The naming strategy output is md5 hashed to avoid any issue with some PersistingStoreInterface implementations.

Examples:

#[MutexRequest(service: 'lock.default.factory', strategy: 'block')]
#[MutexRequest(service: 'lock.default.factory', strategy: 'block', name: 'lock_name')]
  • message (optional)

This is a custom message for the exception in case the lock cannot be acquired.

Examples:

#[MutexRequest(service: 'lock.default.factory', strategy: 'block', message: 'Busy!')]
  • userIsolation (optional, default: false)

This option will add token user context to the name option in order to have isolated locks for different users.

Example:

#[MutexRequest(service: 'lock.default.factory', strategy: 'block', userIsolation: true)]

Note: If security.token_storage is not available and userIsolation is set to true, an exception will be thrown.

Note: Be aware about using userIsolation in anonymous routes.

  • ttl (optional)

Maximum expected lock duration in seconds.

Example:

use IXarlie\MutexBundle\MutexRequest;

class MyController {

    #[MutexRequest(
        service: 'lock.default.factory',
        strategy: 'block',
        name: 'action_name',
        userIsolation: true,
        message: 'Busy!',
        ttl: 20.0
    )]
    public function foo()
    {
        return [];
    }
}