dealerinspire / laravel-redlock
为 Laravel 提供的 Redis 分布式锁
Requires
- php: >=8.0.0
- illuminate/console: >=10.0
- illuminate/support: >=10.0
- predis/predis: ^2.0
Requires (Dev)
- orchestra/testbench: 8.*|9.*
- php-mock/php-mock-mockery: ^1.1
- phpunit/phpunit: ~9.0|^10.5
README
A Laravel-friendly implementation of the Redis Redlock algorithm for distributed lock management.
致谢
此库最初由 LibiChai 基于 antirez 开发的 RedLock 算法构建。该库由 That's Us, Inc. 的团队重新设计。该项目已被 Dealer Inspire Inc. 分支并维护。
安装
composer require dealerinspire/laravel-redlock
RedLockServiceProvider
应由 Laravel 自动发现。如果未发现,请将DealerInspire\RedLock\RedLockServiceProvider::class,
添加到config/app.php
中的providers
数组。- 享受吧!
兼容性
很简单!
在任何标量上设置锁。如果 lock()
方法返回 false,则未获取到锁。
存储 lock()
方法的返回结果。使用此值通过 unlock()
释放锁。
示例
此示例将键 "1" 设置为 3 秒过期时间的锁。
如果获取了锁,则执行一些工作并释放锁。
use DealerInspire\RedLock\Facades\RedLock; $product_id = 1; $lock_object = RedLock::lock($product_id, 3000); if ($lock_object) { $order->submit($product_id); RedLock::unlock($lock_token); // or $lock_object->unlock(); }
刷新
使用 refreshLock()
重新获取并延长锁的时间。
use DealerInspire\RedLock\Facades\RedLock; $product_ids = [1, 2, 3, 5, 7]; $lock_object = RedLock::lock('order-submitter', 3000); while ($product_ids && $lock_object) { $order->submit(array_shift($product_ids)); $lock_object = RedLock::refreshLock($lock_object); } RedLock::unlock($lock_object); // or $lock_object->unlock();
使用闭包更容易
使用 runLocked()
获取更简洁的语法。该方法返回闭包的结果,或者在无法获取锁的情况下返回 false。
use DealerInspire\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 DealerInspire\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 队列中的作业,您可能希望避免同时排队相同的作业。
DealerInspire\RedLock\Traits\QueueWithoutOverlap
trait 以最小的更改提供了此功能。通常只需要两个更改。
- 将
use DealerInspire\RedLock\Traits\QueueWithoutOverlap
作为 trait 使用 - 将
handle()
方法更改为handleSync()
use DealerInspire\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()
方法。
此 trait 还提供了一个名为 refreshLock()
的刷新方法。如果 refreshLock()
无法刷新锁,将抛出异常并使作业失败。
最后,您可以使用 $lock_time
属性将锁的超时时间从默认的 300 秒更改为另一个值。
use DealerInspire\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); } } }
贡献
如果您发现了一个错误或想为代码或文档做出贡献,您可以提交一个 问题 或一个 拉取请求 来帮助。
开发
开发是通过简单使用官方 PHP 和 Composer 镜像完成的。
入门
- 拉取存储库。
- 使用
bin/composer install
安装依赖项。 - 就这样!
运行测试
可以使用 bin/php vendor/bin/phpunit
运行测试。