aira-virtual / laravel-redlock
为Laravel提供的Redis分布式锁
Requires
- php: >=7.0
- illuminate/console: ^5.6
- illuminate/support: ^5.6
- predis/predis: ^1.1
Requires (Dev)
- orchestra/testbench: ^3.8.0
- php-mock/php-mock-mockery: ^1.1
- phpunit/phpunit: ~7.0
This package is not auto-updated.
Last update: 2024-09-27 15:22:42 UTC
README
使用Redis提供通用的锁定机制。实现了Redis提出的锁定标准。
致谢
这个库最初由LibiChai基于antirez开发的Redlock算法构建。该库由That's Us, Inc.团队重新设计。
安装
- composer require aira-virtual/laravel-redlock
- 将ThatsUs\RedLock\RedLockServiceProvider::class,添加到config/app.php中的providers数组中
- 享受吧!
很简单!
对任何标量设置锁。如果lock()方法返回false,则未获取到锁。
存储lock()方法的返回结果。使用此值通过unlock()释放锁。
示例
此示例设置了一个带有3秒过期时间的锁,锁定键为"1"。
如果获取到锁,则执行一些工作并释放锁。
 use ThatsUs\RedLock\Facades\RedLock;
 $product_id = 1;
 $lock_token = RedLock::lock($product_id, 3000);
 
 if ($lock_token) {
     $order->submit($product_id);
     RedLock::unlock($lock_token);
 }
刷新
使用refreshLock()重新获取并扩展锁的持续时间。
 use ThatsUs\RedLock\Facades\RedLock;
 $product_ids = [1, 2, 3, 5, 7];
 $lock_token = RedLock::lock('order-submitter', 3000);
 
 while ($product_ids && $lock_token) {
     $order->submit(array_shift($product_ids));
     $lock_token = RedLock::refreshLock($lock_token);
 }
 RedLock::unlock($lock_token);
使用闭包更简单
使用runLocked()获得更简洁的语法。该方法返回闭包的结果,或者在无法获取锁时返回false。
 use ThatsUs\RedLock\Facades\RedLock;
 $product_id = 1;
 $result = RedLock::runLocked($product_id, 3000, function () use ($order, $product_id) {
     $order->submit($product_id);
     return true;
 });
 echo $result ? 'Worked!' : 'Lock not acquired.';
使用闭包刷新
在闭包中使用时,您可以轻松刷新令牌。闭包的第一个参数是$refresh。在需要刷新时调用它。如果锁无法刷新,$refresh()将退出闭包。
 use ThatsUs\RedLock\Facades\RedLock;
 $product_ids = [1, 2, 3, 5, 7];
 $result = RedLock::runLocked($product_id, 3000, function ($refresh) use ($order, $product_ids) {
     foreach ($product_ids as $product_id) {
         $refresh();
         $order->submit($product_id);
     }
     return true;
 });
 echo $result ? 'Worked!' : 'Lock lost or never acquired.';
轻松锁定队列作业
如果您正在Laravel队列上运行作业,您可能希望避免同时将相同的作业排队。
ThatsUs\RedLock\Traits\QueueWithoutOverlap特质通过很少更改您的作业提供此功能。通常只需要更改两次。
- 使用特质use ThatsUs\RedLock\Traits\QueueWithoutOverlap
- 将handle()方法改为handleSync()
use ThatsUs\RedLock\Traits\QueueWithoutOverlap;
class OrderProductJob
{
    use QueueWithoutOverlap;
    public function __construct($order, $product_id)
    {
        $this->order = $order;
        $this->product_id = $product_id;
    }
    public function handleSync()
    {
        $this->order->submit($this->product_id);
    }
}
有时还需要指定一个getLockKey()方法。此方法必须返回需要锁定的字符串。
通常不需要这样做,因为锁键可以自动生成。但如果作业的数据不易转换为字符串,您必须定义getLockKey()方法。
该特质还提供了一个名为refreshLock()的刷新方法。如果refreshLock()无法刷新锁,则抛出异常并使作业失败。
最后,您可以使用$lock_time属性将锁的超时时间从默认的300秒更改为其他值。
use ThatsUs\RedLock\Traits\QueueWithoutOverlap;
class OrderProductsJob
{
    use QueueWithoutOverlap;
    protected $lock_time = 600; // 10 minutes in seconds
    public function __construct($order, array $product_ids)
    {
        $this->order = $order;
        $this->product_ids = $product_ids;
    }
    // We need to define getLockKey() because $product_ids is an array and the
    // automatic key generator can't deal with arrays.
    protected function getLockKey()
    {
        $product_ids = implode(',', $this->product_ids);
        return "OrderProductsJob:{$this->order->id}:{$product_ids}";
    }
    public function handleSync()
    {
        foreach ($this->product_ids as $product_id) {
            $this->refreshLock();
            $this->order->submit($product_id);
        }
    }
}
贡献
如果您发现错误或想为代码或文档做出贡献,您可以通过提交问题或pull请求来帮助。