amiralii / laravel-redlock
为 Laravel 提供的 Redis 分布式锁
Requires
- php: ^7.1.3
- illuminate/console: ^8.1
- illuminate/support: ^8.1
- predis/predis: ^1.1
Requires (Dev)
- orchestra/testbench: ~3.6
- php-mock/php-mock-mockery: ^2
- phpunit/phpunit: ~7.0
This package is not auto-updated.
Last update: 2024-10-02 20:29:07 UTC
README
使用 Redis 提供通用锁定机制。实现了 Redis 提出的锁定标准。
鸣谢
此库最初由 LibiChai 在 antirez 开发的 Redlock 算法基础上构建。该库由 That's Us, Inc. 团队重构。
安装
"parsadp/laravel-redlock": "^4.0.0"
"composer update"
- 将
Amiralii\RedLock\RedLockServiceProvider::class,
添加到 config/app.php 文件中的providers
数组中 - 享受吧!
很简单!
在任何标量上设置锁。如果 lock()
方法返回 false,则未获取到锁。
存储 lock()
方法的返回结果。使用此值使用 unlock()
释放锁。
示例
此示例使用 3 秒过期时间在键 "1" 上设置锁。
如果获取了锁,则执行一些工作并释放锁。
use Amiralii\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 Amiralii\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 Amiralii\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 Amiralii\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 队列上运行作业,您可能希望避免同时排队相同的作业。
Amiralii\RedLock\Traits\QueueWithoutOverlap
特性通过少量修改您的作业提供了此功能。通常只需要更改两次。
- 作为特性使用
use Amiralii\RedLock\Traits\QueueWithoutOverlap
- 将
handle()
方法更改为handleSync()
use Amiralii\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 Amiralii\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 request 来帮助。