注意:要使用此功能,您的应用程序必须使用
memcached
、redis
、dynamicodb
、database
、file
或array
缓存驱动程序作为应用程序的默认缓存驱动程序。
此外,所有服务器都必须与同一中央缓存服务器通信。
使用“数据库”缓存驱动程序时,您需要设置一个表来包含应用程序的缓存锁。您将在下表中找到一个示例 Schema
声明:
Schema::create('cache_locks', function ($table) {
$table->string('key')->primary();
$table->string('owner');
$table->integer('expiration');
});
原子锁允许操作分布式锁而不用担心竞争条件。例如,Laravel Forge 使用原子锁来确保服务器上一次只执行一个远程任务。您可以使用 Cache::lock
方法创建和管理锁:
use Illuminate\Support\Facades\Cache;
$lock = Cache::lock('foo', 10);
if ($lock->get()) {
// 锁定 10 秒...
$lock->release();
}
get
方法也接受一个闭包。闭包执行后,Laravel 会自动释放锁:
Cache::lock('foo')->get(function () {
// 锁定无限期获得并自动释放...
});
如果在您请求时锁不可用,您可以指示 Laravel 等待指定的秒数。如果在指定的时间限制内无法获取锁,则会抛出 Illuminate\Contracts\Cache\LockTimeoutException
:
use Illuminate\Contracts\Cache\LockTimeoutException;
$lock = Cache::lock('foo', 10);
try {
$lock->block(5);
// 等待最多 5 秒后获得锁定...
} catch (LockTimeoutException $e) {
// 无法获取锁...
} finally {
optional($lock)->release();
}
上面的例子可以通过将闭包传递给 block
方法来简化。当一个闭包被传递给这个方法时,Laravel 将尝试在指定的秒数内获取锁,并在闭包执行后自动释放锁:
Cache::lock('foo', 10)->block(5, function () {
// 等待最多 5 秒后获得锁定...
});
有时,您可能希望在一个进程中获取锁并在另一个进程中释放它。例如,您可能在 Web 请求期间获取锁,并希望在由该请求触发的排队作业结束时释放锁。在这种情况下,您应该将锁的作用域「owner 令牌」传递给排队的作业,以便作业可以使用给定的令牌重新实例化锁。
在下面的示例中,如果成功获取锁,我们将调度一个排队的作业。 此外,我们将通过锁的 owner
方法将锁的所有者令牌传递给排队的作业:
$podcast = Podcast::find($id);
$lock = Cache::lock('processing', 120);
if ($lock->get()) {
ProcessPodcast::dispatch($podcast, $lock->owner());
}
在我们应用程序的 ProcessPodcast
作业中,我们可以使用所有者令牌恢复和释放锁:
Cache::restoreLock('processing', $this->owner)->release();
如果你想释放一个锁而不考虑它的当前所有者,你可以使用 forceRelease
方法:
Cache::lock('processing')->forceRelease();