Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Resource Lock Bundle Laravel Package

aboutcoders/resource-lock-bundle

Symfony bundle providing a resource locking system backed by ORM. Configure a default lock manager and optional custom managers with prefixes, then fetch lock manager services from the container to set, get, and check locks across your app.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require aboutcoders/resource-lock-bundle:dev-master
    

    Add the bundle to config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):

    Abc\Bundle\ResourceLockBundle\AbcResourceLockBundle::class => ['all' => true],
    
  2. Basic Configuration: Add to config/packages/aboutcoders_resource_lock.yaml (Symfony 4+):

    abc_resource_lock:
        db_driver: orm  # or 'pdo' for raw PDO
    
  3. First Use Case: Lock a resource (e.g., inventory item) in a service:

    use Abc\Bundle\ResourceLockBundle\Lock\LockManagerInterface;
    
    class InventoryService {
        public function __construct(private LockManagerInterface $lockManager) {}
    
        public function updateInventory(string $itemId, int $quantity) {
            $lock = $this->lockManager->getLock('inventory_' . $itemId);
            if (!$lock->isLocked()) {
                $lock->lock(); // Acquire lock
            }
    
            // Critical section: Update inventory
            $this->update($itemId, $quantity);
    
            $lock->release(); // Release lock
        }
    }
    

Implementation Patterns

Core Workflows

  1. Locking Strategies:

    • Exclusive Locks: Use for write operations (e.g., inventory updates).
      $lock = $lockManager->getLock('resource_key');
      $lock->lock(); // Blocks until lock is acquired
      
    • Shared Locks: Use for read-heavy operations (if supported by the driver).
      $lock = $lockManager->getLock('resource_key', Lock::SHARED);
      
  2. Lock Scopes:

    • Global Locks: Use a generic prefix (e.g., inventory_).
    • Custom Managers: Define scoped locks via config:
      abc_resource_lock:
          managers:
              inventory:
                  prefix: 'inventory_'
      
      Access via:
      $inventoryLockManager = $container->get('abc.resource_lock.lock_manager_inventory');
      
  3. Lock Expiration:

    • Set TTL (Time-To-Live) for automatic release:
      $lock = $lockManager->getLock('resource_key', Lock::TTL_30); // 30-second lock
      
  4. Retry Logic:

    • Implement exponential backoff for failed lock attempts:
      $attempts = 0;
      $maxAttempts = 3;
      while (!$lock->isLocked() && $attempts < $maxAttempts) {
          $lock->lock();
          $attempts++;
          if (!$lock->isLocked()) {
              sleep(2 ** $attempts); // Exponential delay
          }
      }
      
  5. Integration with Doctrine:

    • Use db_driver: orm to leverage Doctrine for lock storage.
    • Example: Lock a Product entity:
      $lock = $lockManager->getLock('product_' . $product->getId());
      

Common Use Cases

  • Concurrent Order Processing: Lock order IDs to prevent duplicate processing.
  • Rate Limiting: Lock user IDs to enforce API rate limits.
  • Batch Jobs: Lock queues to avoid parallel execution of the same job.

Gotchas and Tips

Pitfalls

  1. Deadlocks:

    • Always acquire locks in a consistent order (e.g., alphabetical by resource ID).
    • Avoid nested locks (e.g., locking A then B in one method, and B then A in another).
  2. Lock Leaks:

    • Ensure locks are always released (use try-finally or dependency injection for cleanup):
      try {
          $lock->lock();
          // Critical section
      } finally {
          $lock->release();
      }
      
    • For Symfony services, use onKernelTerminate to release locks if the request fails.
  3. Driver Limitations:

    • PDO Driver: Less portable than ORM; ensure transactions are handled manually.
    • ORM Driver: Requires Doctrine; may cause performance issues with high lock contention.
  4. Configuration Quirks:

    • If using db_driver: orm, ensure your Doctrine entity manager is configured.
    • Custom managers must be defined in config; dynamic creation isn’t supported.
  5. Lock Timeouts:

    • Default TTL is infinite. Set explicit TTLs to avoid stale locks:
      abc_resource_lock:
          default_ttl: 300  # 5 minutes
      

Debugging Tips

  1. Check Lock Status:

    if ($lock->isLocked()) {
        echo "Locked by: " . $lock->getOwner(); // If owner tracking is enabled
    }
    
  2. Log Lock Operations: Add a decorator to the LockManagerInterface to log lock attempts:

    $lockManager->getLock('key')->lock(); // Logs to monolog
    
  3. Test Lock Contention: Use PHPUnit to simulate concurrent requests:

    $this->parallel()->with([1, 2, 3])->run(function ($i) {
        $lock = $lockManager->getLock('test_lock');
        $lock->lock();
        // Assert lock is held
    });
    

Extension Points

  1. Custom Lock Storage: Extend the LockStorageInterface to support Redis, Memcached, etc.:

    class RedisLockStorage implements LockStorageInterface {
        // Implement lock logic using Redis
    }
    
  2. Event Listeners: Trigger events on lock acquisition/release:

    # config/services.yaml
    services:
        App\EventListener\LockListener:
            tags:
                - { name: kernel.event_listener, event: abc.resource_lock.lock_acquired, method: onLockAcquired }
    
  3. Lock Metadata: Store additional metadata (e.g., user ID, timestamp) by extending the Lock class:

    class ExtendedLock extends Lock {
        protected $metadata;
    
        public function setMetadata(array $metadata) {
            $this->metadata = $metadata;
        }
    }
    
  4. Fallback Mechanisms: Implement a fallback to a simpler lock (e.g., file-based) if the DB driver fails:

    try {
        $lockManager->getLock('key')->lock();
    } catch (LockException $e) {
        file_put_contents('/tmp/fallback_lock', 'locked');
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui